From: Christian Couder <hidden> Date: 2017-02-27 18:02:34
Goal
~~~~
We want to make it possible to use the split-index feature
automatically by just setting a new "core.splitIndex" configuration
variable to true.
This can be valuable as split-index can help significantly speed up
`git rebase` especially along with the work to libify `git apply`
that has been merged to master
(see https://github.com/git/git/commit/81358dc238372793b1590efa149cc1581d1fbd98)
and is now in v2.11.
Design
~~~~~~
The design is similar as the previous work that introduced
"core.untrackedCache".
The new "core.splitIndex" configuration option can be either true,
false or undefined which is the default.
When it is true, the split index is created, if it does not already
exists, when the index is read. When it is false, the split index is
removed if it exists, when the index is read. Otherwise it is left as
is.
Along with this new configuration variable, the two following options
are also introduced:
- splitIndex.maxPercentChange
This is to avoid having too many changes accumulating in the split
index while in split index mode. The git-update-index
documentation says:
If split-index mode is already enabled and `--split-index` is
given again, all changes in $GIT_DIR/index are pushed back to
the shared index file.
but it is probably better to not expect the user to think about it
and to have a mechanism that pushes back all changes to the shared
index file automatically when some threshold is reached.
The default threshold is when the number of entries in the split
index file reaches 20% of the number of entries in the shared
index file. The new "splitIndex.maxPercentChange" config option
lets people tweak this value.
- splitIndex.sharedIndexExpire
To make sure that old sharedindex files are eventually removed
when a new one has been created, we "touch" the shared index file
every time a split index file using the shared index file is
either created or read from. Then we can delete shared indexes
with an mtime older than one week (by default), when we create a
new shared index file. The new "splitIndex.sharedIndexExpire"
config option lets people tweak this grace period.
This idea was suggested by Duy in:
https://public-inbox.org/git/CACsJy8BqMFASHf5kJgUh+bd7XG98CafNydE964VJyPXz-emEvA@mail.gmail.com/
and after some experiments, I agree that it is much simpler than
what I thought could be done during our discussion.
Junio also thinks that we have to do "time-based GC" in:
https://public-inbox.org/git/xmqqeg33ccjj.fsf@gitster.mtv.corp.google.com/
Note that this patch series doesn't address a leak when removing a
split-index, but Duy wrote that he has a patch to fix this leak:
https://public-inbox.org/git/CACsJy8AisF2ZVs7JdnVFp5wdskkbVQQQ=DBq5UzE1MOsCfBMtQ@mail.gmail.com/
Highlevel view of the patches in the series
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Except for patch 1/22 and 1/22, there are 3 big steps, one for each
new configuration variable introduced.
There only small differences between this patch series and the v3
patch series sent a few months ago.
- Patch 1/22 marks a message for translation. It is not new and
can be applied separately.
- Patch 2/22 improves the existing indentation style of t1700 by
using different here document style. It is a new preparatory
patch suggested by Junio.
Step 1 is:
- Patches 3/22 to 6/22 introduce the functions that are reading
the "core.splitIndex" configuration variable and tweaking the
split index depending on its value.
- Patch 7/22 adds a few tests for the new feature.
- Patches 8/22 and 9/22 add some documentation for the new
feature.
There is no change since v3 in this step.
Step 2 is:
- Patches 10/22 and 11/22 introduce the functions that are reading
the "splitIndex.maxPercentChange" configuration variable and
regenerating a new shared index file depending on its value.
Patch 11/12 has a few changes suggested by Junio since v3, see
https://public-inbox.org/git/CAP8UFD3_1EN=0EsD12Cew1MuW8yhtPAZw0M_g3wmvKFk-uGXxw@mail.gmail.com/
- Patch 12/22 adds a few tests for the new feature.
- Patch 13/22 add some documentation for the new feature. The
added documentation has been reworded a little bit since v3 as
suggested by Junio.
Step 3 is:
- Patches 14/22 to 17/22 introduce the functions that are reading
the "splitIndex.sharedIndexExpire" configuration variable and
expiring old shared index files depending on its value.
Patch 15/22 has a few changes suggested by Ramsay and Junio in
http://public-inbox.org/git/a1a44640-ff6c-2294-72ac-46322eff8505@ramsayjones.plus.com/http://public-inbox.org/git/xmqqbmunq6mg.fsf@gitster.mtv.corp.google.com/
The main change is that the new freshen_shared_index() will now
warn if the split-index file has been written but the shared
index file could't be freshened.
Another change is that in 17/22 the new
"splitIndex.sharedIndexExpire" config variable now defaults to
"2.weeks.ago" instead of "one.week.ago" in v3.
- Patch 18/22 adds a few tests for the new feature. It is changed
a bit to account for the change in 17/22.
Also some flakyness in one of the tests has been fixed by using
a 5 second, instead of 1 second, delay, thanks to Ramsay and
Peff, see
http://public-inbox.org/git/818851a6-c3ef-618e-4146-518fbe6bd837@ramsayjones.plus.com/
- Patches 19/22 and 20/22 were new patches in v3. They update the
mtime of the shared index file when a split index based on the
shared index file is read from. 19/22 is a refactoring to make
the actual change in 20/22 easier.
Patch 20/22 has been changed a little bit since v3 to take into
account changes in 17/22.
- Patches 21/22 and 22/22 add some documentation for the new
feature. Patch 21/22 has been changed to avoid using "mtime" as
suggested by Junio.
Links
~~~~~
This patch series is also available here:
https://github.com/chriscool/git/commits/config-split-index
The previous versions were:
RFC: https://github.com/chriscool/git/commits/config-split-index7
v1: https://github.com/chriscool/git/commits/config-split-index72
v2: https://github.com/chriscool/git/commits/config-split-index99
v3: https://github.com/chriscool/git/commits/config-split-index102
On the mailing list the related patch series and discussions were:
RFC: https://public-inbox.org/git/20160711172254.13439-1-chriscool@tuxfamily.org/
v1: https://public-inbox.org/git/20161023092648.12086-1-chriscool@tuxfamily.org/
v2: https://public-inbox.org/git/20161217145547.11748-1-chriscool@tuxfamily.org/
v3: https://public-inbox.org/git/20161226102222.17150-1-chriscool@tuxfamily.org/
Christian Couder (22):
config: mark an error message up for translation
t1700: change here document style
config: add git_config_get_split_index()
split-index: add {add,remove}_split_index() functions
read-cache: add and then use tweak_split_index()
update-index: warn in case of split-index incoherency
t1700: add tests for core.splitIndex
Documentation/config: add information for core.splitIndex
Documentation/git-update-index: talk about core.splitIndex config var
config: add git_config_get_max_percent_split_change()
read-cache: regenerate shared index if necessary
t1700: add tests for splitIndex.maxPercentChange
Documentation/config: add splitIndex.maxPercentChange
sha1_file: make check_and_freshen_file() non static
read-cache: touch shared index files when used
config: add git_config_get_expiry() from gc.c
read-cache: unlink old sharedindex files
t1700: test shared index file expiration
read-cache: refactor read_index_from()
read-cache: use freshen_shared_index() in read_index_from()
Documentation/config: add splitIndex.sharedIndexExpire
Documentation/git-update-index: explain splitIndex.*
Documentation/config.txt | 29 ++++
Documentation/git-update-index.txt | 43 ++++-
builtin/gc.c | 15 +-
builtin/update-index.c | 25 +--
cache.h | 8 +
config.c | 42 ++++-
read-cache.c | 157 ++++++++++++++++--
sha1_file.c | 2 +-
split-index.c | 22 +++
split-index.h | 2 +
t/t1700-split-index.sh | 324 +++++++++++++++++++++++++++----------
11 files changed, 539 insertions(+), 130 deletions(-)
--
2.12.0.22.g0672473d40
From: Christian Couder <hidden> Date: 2017-02-27 18:02:10
Also use the functions in cmd_update_index() in
builtin/update-index.c.
These functions will be used in a following commit to tweak
our use of the split-index feature depending on the setting
of a configuration variable.
Signed-off-by: Christian Couder <redacted>
---
builtin/update-index.c | 18 ++++++------------
split-index.c | 22 ++++++++++++++++++++++
split-index.h | 2 ++
3 files changed, 30 insertions(+), 12 deletions(-)
From: Christian Couder <hidden> Date: 2017-02-27 18:02:12
This new function will be used in a following commit to know
if we want to use the split index feature or not.
Signed-off-by: Christian Couder <redacted>
---
cache.h | 1 +
config.c | 10 ++++++++++
2 files changed, 11 insertions(+)
@@ -1882,6 +1882,7 @@ extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);externintgit_config_get_maybe_bool(constchar*key,int*dest);externintgit_config_get_pathname(constchar*key,constchar**dest);externintgit_config_get_untracked_cache(void);+externintgit_config_get_split_index(void);/**Thisisahackfortestprogramsliketest-dump-untracked-cacheto
@@ -1736,6 +1736,16 @@ int git_config_get_untracked_cache(void)return-1;/* default value */}+intgit_config_get_split_index(void)+{+intval;++if(!git_config_get_maybe_bool("core.splitindex",&val))+returnval;++return-1;/* default value */+}+NORETURNvoidgit_die_config_linenr(constchar*key,constchar*filename,intlinenr){
From: Christian Couder <hidden> Date: 2017-02-27 18:02:16
This new function will be used in a following commit to get the
value of the "splitIndex.maxPercentChange" config variable.
Signed-off-by: Christian Couder <redacted>
---
cache.h | 1 +
config.c | 15 +++++++++++++++
2 files changed, 16 insertions(+)
@@ -1746,6 +1746,21 @@ int git_config_get_split_index(void)return-1;/* default value */}+intgit_config_get_max_percent_split_change(void)+{+intval=-1;++if(!git_config_get_int("splitindex.maxpercentchange",&val)){+if(0<=val&&val<=100)+returnval;++returnerror(_("splitIndex.maxPercentChange value '%d' "+"should be between 0 and 100"),val);+}++return-1;/* default value */+}+NORETURNvoidgit_die_config_linenr(constchar*key,constchar*filename,intlinenr){
From: Christian Couder <hidden> Date: 2017-02-27 18:02:19
When writing a new split-index and there is a big number of cache
entries in the split-index compared to the shared index, it is a
good idea to regenerate the shared index.
By default when the ratio reaches 20%, we will push back all
the entries from the split-index into a new shared index file
instead of just creating a new split-index file.
The threshold can be configured using the
"splitIndex.maxPercentChange" config variable.
We need to adjust the existing tests in t1700 by setting
"splitIndex.maxPercentChange" to 100 at the beginning of t1700,
as the existing tests are assuming that the shared index is
regenerated only when `git update-index --split-index` is used.
Signed-off-by: Christian Couder <redacted>
---
read-cache.c | 32 ++++++++++++++++++++++++++++++++
t/t1700-split-index.sh | 1 +
2 files changed, 33 insertions(+)
@@ -2212,6 +2212,36 @@ static int write_shared_index(struct index_state *istate,returnret;}+staticconstintdefault_max_percent_split_change=20;++staticinttoo_many_not_shared_entries(structindex_state*istate)+{+inti,not_shared=0;+intmax_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;+case0:+return1;/* 0% means always write a new shared index */+case100:+return0;/* 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++){+structcache_entry*ce=istate->cache[i];+if(!ce->index)+not_shared++;+}++return(int64_t)istate->cache_nr*max_split<(int64_t)not_shared*100;+}+intwrite_locked_index(structindex_state*istate,structlock_file*lock,unsignedflags){
From: Christian Couder <hidden> Date: 2017-02-27 18:02:22
This will make us use the split-index feature or not depending
on the value of the "core.splitIndex" config variable.
Signed-off-by: Christian Couder <redacted>
---
read-cache.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
From: Christian Couder <hidden> Date: 2017-02-27 18:02:23
When users are using `git update-index --(no-)split-index`, they
may expect the split-index feature to be used or not according to
the option they just used, but this might not be the case if the
new "core.splitIndex" config variable has been set. In this case
let's warn about what will happen and why.
Signed-off-by: Christian Couder <redacted>
---
builtin/update-index.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
@@ -1099,12 +1099,21 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)}if(split_index>0){+if(git_config_get_split_index()==0)+warning(_("core.splitIndex is set to false; "+"remove or change it, if you really want to "+"enable split index"));if(the_index.split_index)the_index.cache_changed|=SPLIT_INDEX_ORDERED;elseadd_split_index(&the_index);-}elseif(!split_index)+}elseif(!split_index){+if(git_config_get_split_index()==1)+warning(_("core.splitIndex is set to true; "+"remove or change it, if you really want to "+"disable split index"));remove_split_index(&the_index);+}switch(untracked_cache){caseUC_UNSPECIFIED:
@@ -334,6 +334,10 @@ core.trustctime:: crawlers and some backup systems). See linkgit:git-update-index[1]. True by default.+core.splitIndex::+ If true, the split-index feature of the index will be used.+ See linkgit:git-update-index[1]. False by default.+ core.untrackedCache:: Determines what to do about the untracked cache feature of the index. It will be kept, if this variable is unset or set to
@@ -171,6 +171,12 @@ may not support it yet. given again, all changes in $GIT_DIR/index are pushed back to the shared index file. This mode is designed for very large indexes that take a significant amount of time to read or write.+++These options take effect whatever the value of the `core.splitIndex`+configuration variable (see linkgit:git-config[1]). But a warning is+emitted when the change goes against the configured value, as the+configured value will take effect next time the index is read and this+will remove the intended effect of the option. --untracked-cache:: --no-untracked-cache::
From: Christian Couder <hidden> Date: 2017-02-27 18:02:36
This improves test indentation by getting rid of the outdated
here document style.
Signed-off-by: Christian Couder <redacted>
---
t/t1700-split-index.sh | 170 ++++++++++++++++++++++++-------------------------
1 file changed, 85 insertions(+), 85 deletions(-)
@@ -32,51 +32,51 @@ test_expect_success 'add one file' ':>one&&gitupdate-index--addone&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-100644$EMPTY_BLOB0one-EOF+cat>ls-files.expect<<-EOF&&+100644$EMPTY_BLOB0one+EOFtest_cmpls-files.expectls-files.actual&&test-dump-split-index.git/index|sed"/^own/d">actual&&-cat>expect<<EOF&&-base$base-100644$EMPTY_BLOB0one-replacements:-deletions:-EOF+cat>expect<<-EOF&&+base$base+100644$EMPTY_BLOB0one+replacements:+deletions:+EOFtest_cmpexpectactual' test_expect_success'disable split index''gitupdate-index--no-split-index&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-100644$EMPTY_BLOB0one-EOF+cat>ls-files.expect<<-EOF&&+100644$EMPTY_BLOB0one+EOFtest_cmpls-files.expectls-files.actual&&BASE=$(test-dump-split-index.git/index|grep"^own"|sed"s/own/base/")&&test-dump-split-index.git/index|sed"/^own/d">actual&&-cat>expect<<EOF&&-notasplitindex-EOF+cat>expect<<-EOF&&+notasplitindex+EOFtest_cmpexpectactual' test_expect_success'enable split index again, "one" now belongs to base index"''gitupdate-index--split-index&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-100644$EMPTY_BLOB0one-EOF+cat>ls-files.expect<<-EOF&&+100644$EMPTY_BLOB0one+EOFtest_cmpls-files.expectls-files.actual&&test-dump-split-index.git/index|sed"/^own/d">actual&&-cat>expect<<EOF&&-$BASE-replacements:-deletions:-EOF+cat>expect<<-EOF&&+$BASE+replacements:+deletions:+EOFtest_cmpexpectactual'
@@ -84,18 +84,18 @@ test_expect_success 'modify original file, base index untouched' 'echomodified>one&&gitupdate-indexone&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0one-EOF+cat>ls-files.expect<<-EOF&&+1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0one+EOFtest_cmpls-files.expectls-files.actual&&test-dump-split-index.git/index|sed"/^own/d">actual&&-q_to_tab>expect<<EOF&&-$BASE-1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0Q-replacements:0-deletions:-EOF+q_to_tab>expect<<-EOF&&+$BASE+1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0Q+replacements:0+deletions:+EOFtest_cmpexpectactual'
@@ -103,54 +103,54 @@ test_expect_success 'add another file, which stays index' ':>two&&gitupdate-index--addtwo&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0one-100644$EMPTY_BLOB0two-EOF+cat>ls-files.expect<<-EOF&&+1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0one+100644$EMPTY_BLOB0two+EOFtest_cmpls-files.expectls-files.actual&&test-dump-split-index.git/index|sed"/^own/d">actual&&-q_to_tab>expect<<EOF&&-$BASE-1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0Q-100644$EMPTY_BLOB0two-replacements:0-deletions:-EOF+q_to_tab>expect<<-EOF&&+$BASE+1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0Q+100644$EMPTY_BLOB0two+replacements:0+deletions:+EOFtest_cmpexpectactual' test_expect_success'remove file not in base index''gitupdate-index--force-removetwo&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0one-EOF+cat>ls-files.expect<<-EOF&&+1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0one+EOFtest_cmpls-files.expectls-files.actual&&test-dump-split-index.git/index|sed"/^own/d">actual&&-q_to_tab>expect<<EOF&&-$BASE-1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0Q-replacements:0-deletions:-EOF+q_to_tab>expect<<-EOF&&+$BASE+1006442e0996000b7e9019eabcad29391bf0f5c7702f0b0Q+replacements:0+deletions:+EOFtest_cmpexpectactual' test_expect_success'remove file in base index''gitupdate-index--force-removeone&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-EOF+cat>ls-files.expect<<-EOF&&+EOFtest_cmpls-files.expectls-files.actual&&test-dump-split-index.git/index|sed"/^own/d">actual&&-cat>expect<<EOF&&-$BASE-replacements:-deletions:0-EOF+cat>expect<<-EOF&&+$BASE+replacements:+deletions:0+EOFtest_cmpexpectactual'
@@ -158,18 +158,18 @@ test_expect_success 'add original file back' ':>one&&gitupdate-index--addone&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-100644$EMPTY_BLOB0one-EOF+cat>ls-files.expect<<-EOF&&+100644$EMPTY_BLOB0one+EOFtest_cmpls-files.expectls-files.actual&&test-dump-split-index.git/index|sed"/^own/d">actual&&-cat>expect<<EOF&&-$BASE-100644$EMPTY_BLOB0one-replacements:-deletions:0-EOF+cat>expect<<-EOF&&+$BASE+100644$EMPTY_BLOB0one+replacements:+deletions:0+EOFtest_cmpexpectactual'
@@ -177,26 +177,26 @@ test_expect_success 'add new file' ':>two&&gitupdate-index--addtwo&&gitls-files--stage>actual&&-cat>expect<<EOF&&-100644$EMPTY_BLOB0one-100644$EMPTY_BLOB0two-EOF+cat>expect<<-EOF&&+100644$EMPTY_BLOB0one+100644$EMPTY_BLOB0two+EOFtest_cmpexpectactual' test_expect_success'unify index, two files remain''gitupdate-index--no-split-index&&gitls-files--stage>ls-files.actual&&-cat>ls-files.expect<<EOF&&-100644$EMPTY_BLOB0one-100644$EMPTY_BLOB0two-EOF+cat>ls-files.expect<<-EOF&&+100644$EMPTY_BLOB0one+100644$EMPTY_BLOB0two+EOFtest_cmpls-files.expectls-files.actual&&test-dump-split-index.git/index|sed"/^own/d">actual&&-cat>expect<<EOF&&-notasplitindex-EOF+cat>expect<<-EOF&&+notasplitindex+EOFtest_cmpexpectactual'
From: Christian Couder <hidden> Date: 2017-02-27 18:08:51
This function will be used in a commit soon, so let's make
it available globally.
Signed-off-by: Christian Couder <redacted>
---
cache.h | 3 +++
sha1_file.c | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
@@ -1229,6 +1229,9 @@ extern int has_pack_index(const unsigned char *sha1);externvoidassert_sha1_type(constunsignedchar*sha1,enumobject_typeexpect);+/* Helper to check and "touch" a file */+externintcheck_and_freshen_file(constchar*fn,intfreshen);+externconstsignedcharhexval_table[256];staticinlineunsignedinthexval(unsignedcharc){
From: Christian Couder <hidden> Date: 2017-02-27 18:11:43
This function will be used in a following commit to get the expiration
time of the shared index files from the config, and it is generic
enough to be put in "config.c".
Signed-off-by: Christian Couder <redacted>
---
builtin/gc.c | 15 ++-------------
cache.h | 3 +++
config.c | 13 +++++++++++++
3 files changed, 18 insertions(+), 13 deletions(-)
@@ -1888,6 +1888,9 @@ extern int git_config_get_untracked_cache(void);externintgit_config_get_split_index(void);externintgit_config_get_max_percent_split_change(void);+/* This dies if the configured or default date is in the future */+externintgit_config_get_expiry(constchar*key,constchar**output);+/**Thisisahackfortestprogramsliketest-dump-untracked-cacheto*ensurethattheydonotmodifytheuntrackedcachewhenreadingit.
From: Christian Couder <hidden> Date: 2017-02-27 18:11:44
It looks better and is simpler to review when we don't compute
the same things many times in the function.
It will also help make the following commit simpler.
Signed-off-by: Christian Couder <redacted>
---
read-cache.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
@@ -2853,7 +2853,7 @@ splitIndex.sharedIndexExpire:: The default value is "2.weeks.ago". Note that a shared index file is considered modified (for the purpose of expiration) each time a new split-index file is- created based on it.+ either created based on it or read from it. See linkgit:git-update-index[1]. status.relativePaths::
@@ -163,14 +163,10 @@ may not support it yet. --split-index:: --no-split-index::- Enable or disable split index mode. If enabled, the index is- split into two files, $GIT_DIR/index and $GIT_DIR/sharedindex.<SHA-1>.- Changes are accumulated in $GIT_DIR/index while the shared- index file contains all index entries stays unchanged. If- split-index mode is already enabled and `--split-index` is- given again, all changes in $GIT_DIR/index are pushed back to- the shared index file. This mode is designed for very large- indexes that take a significant amount of time to read or write.+ Enable or disable split index mode. If split-index mode is+ already enabled and `--split-index` is given again, all+ changes in $GIT_DIR/index are pushed back to the shared index+ file. + These options take effect whatever the value of the `core.splitIndex` configuration variable (see linkgit:git-config[1]). But a warning is
@@ -394,6 +390,31 @@ Although this bit looks similar to assume-unchanged bit, its goal is different from assume-unchanged bit's. Skip-worktree also takes precedence over assume-unchanged bit when both are set.+Split index+-----------++This mode is designed for repositories with very large indexes, and+aims at reducing the time it takes to repeatedly write these indexes.++In this mode, the index is split into two files, $GIT_DIR/index and+$GIT_DIR/sharedindex.<SHA-1>. Changes are accumulated in+$GIT_DIR/index, the split index, while the shared index file contains+all index entries and stays unchanged.++All changes in the split index are pushed back to the shared index+file when the number of entries in the split index reaches a level+specified by the splitIndex.maxPercentChange config variable (see+linkgit:git-config[1]).++Each time a new shared index file is created, the old shared index+files are deleted if their modification time is older than what is+specified by the splitIndex.sharedIndexExpire config variable (see+linkgit:git-config[1]).++To avoid deleting a shared index file that is still used, its+modification time is updated to the current time everytime a new split+index based on the shared index file is either created or read from.+ Untracked cache ---------------
From: Christian Couder <hidden> Date: 2017-02-27 18:11:47
This way a share index file will not be garbage collected if
we still read from an index it is based from.
As we need to read the current index before creating a new
one, the tests have to be adjusted, so that we don't expect
an old shared index file to be deleted right away when we
create a new one.
Signed-off-by: Christian Couder <redacted>
---
read-cache.c | 1 +
t/t1700-split-index.sh | 14 +++++++-------
2 files changed, 8 insertions(+), 7 deletions(-)
@@ -313,17 +313,17 @@ test_expect_success 'check splitIndex.maxPercentChange set to 0' ' test_expect_success'shared index files expire after 2 weeks by default'':>ten&&gitupdate-index--addten&&-test$(ls.git/sharedindex.*|wc-l)-gt1&&+test$(ls.git/sharedindex.*|wc-l)-gt2&&just_under_2_weeks_ago=$((5-14*86400))&&test-chmtime=$just_under_2_weeks_ago.git/sharedindex.*&&:>eleven&&gitupdate-index--addeleven&&-test$(ls.git/sharedindex.*|wc-l)-gt1&&+test$(ls.git/sharedindex.*|wc-l)-gt2&&just_over_2_weeks_ago=$((-1-14*86400))&&test-chmtime=$just_over_2_weeks_ago.git/sharedindex.*&&:>twelve&&gitupdate-index--addtwelve&&-test$(ls.git/sharedindex.*|wc-l)=1+test$(ls.git/sharedindex.*|wc-l)-le2' test_expect_success'check splitIndex.sharedIndexExpire set to 16 days''
@@ -331,12 +331,12 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to 16 days' 'test-chmtime=$just_over_2_weeks_ago.git/sharedindex.*&&:>thirteen&&gitupdate-index--addthirteen&&-test$(ls.git/sharedindex.*|wc-l)-gt1&&+test$(ls.git/sharedindex.*|wc-l)-gt2&&just_over_16_days_ago=$((-1-16*86400))&&test-chmtime=$just_over_16_days_ago.git/sharedindex.*&&:>fourteen&&gitupdate-index--addfourteen&&-test$(ls.git/sharedindex.*|wc-l)=1+test$(ls.git/sharedindex.*|wc-l)-le2' test_expect_success'check splitIndex.sharedIndexExpire set to "never" and "now"''
@@ -345,13 +345,13 @@ test_expect_success 'check splitIndex.sharedIndexExpire set to "never" and "now"test-chmtime=$just_10_years_ago.git/sharedindex.*&&:>fifteen&&gitupdate-index--addfifteen&&-test$(ls.git/sharedindex.*|wc-l)-gt1&&+test$(ls.git/sharedindex.*|wc-l)-gt2&&gitconfigsplitIndex.sharedIndexExpirenow&&just_1_second_ago=-1&&test-chmtime=$just_1_second_ago.git/sharedindex.*&&:>sixteen&&gitupdate-index--addsixteen&&-test$(ls.git/sharedindex.*|wc-l)=1+test$(ls.git/sharedindex.*|wc-l)-le2' test_done
@@ -310,4 +310,48 @@ test_expect_success 'check splitIndex.maxPercentChange set to 0' 'test_cmpexpectactual'+test_expect_success'shared index files expire after 2 weeks by default''+:>ten&&+gitupdate-index--addten&&+test$(ls.git/sharedindex.*|wc-l)-gt1&&+just_under_2_weeks_ago=$((5-14*86400))&&+test-chmtime=$just_under_2_weeks_ago.git/sharedindex.*&&+:>eleven&&+gitupdate-index--addeleven&&+test$(ls.git/sharedindex.*|wc-l)-gt1&&+just_over_2_weeks_ago=$((-1-14*86400))&&+test-chmtime=$just_over_2_weeks_ago.git/sharedindex.*&&+:>twelve&&+gitupdate-index--addtwelve&&+test$(ls.git/sharedindex.*|wc-l)=1+'++test_expect_success'check splitIndex.sharedIndexExpire set to 16 days''+gitconfigsplitIndex.sharedIndexExpire"16.days.ago"&&+test-chmtime=$just_over_2_weeks_ago.git/sharedindex.*&&+:>thirteen&&+gitupdate-index--addthirteen&&+test$(ls.git/sharedindex.*|wc-l)-gt1&&+just_over_16_days_ago=$((-1-16*86400))&&+test-chmtime=$just_over_16_days_ago.git/sharedindex.*&&+:>fourteen&&+gitupdate-index--addfourteen&&+test$(ls.git/sharedindex.*|wc-l)=1+'++test_expect_success'check splitIndex.sharedIndexExpire set to "never" and "now"''+gitconfigsplitIndex.sharedIndexExpirenever&&+just_10_years_ago=$((-365*10*86400))&&+test-chmtime=$just_10_years_ago.git/sharedindex.*&&+:>fifteen&&+gitupdate-index--addfifteen&&+test$(ls.git/sharedindex.*|wc-l)-gt1&&+gitconfigsplitIndex.sharedIndexExpirenow&&+just_1_second_ago=-1&&+test-chmtime=$just_1_second_ago.git/sharedindex.*&&+:>sixteen&&+gitupdate-index--addsixteen&&+test$(ls.git/sharedindex.*|wc-l)=1+'+ test_done
@@ -2831,6 +2831,19 @@ showbranch.default:: The default set of branches for linkgit:git-show-branch[1]. See linkgit:git-show-branch[1].+splitIndex.maxPercentChange::+ When the split index feature is used, this specifies the+ percent of entries the split index can contain compared to the+ total number of entries in both the split index and the shared+ index before a new shared index is written.+ The value should be between 0 and 100. If the value is 0 then+ a new shared index is always written, if it is 100 a new+ shared index is never written.+ By default the value is 20, so a new shared index is written+ if the number of entries in the split index would be greater+ than 20 percent of the total number of entries.+ See linkgit:git-update-index[1].+ status.relativePaths:: By default, linkgit:git-status[1] shows paths relative to the current directory. Setting this variable to `false` shows paths
From: Christian Couder <hidden> Date: 2017-02-27 18:59:21
When a split-index file is created, let's update the mtime of the
shared index file that the split-index file is referencing.
In a following commit we will make shared index file expire
depending on their mtime, so updating the mtime makes sure that
the shared index file will not be deleted soon.
Signed-off-by: Christian Couder <redacted>
---
read-cache.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
@@ -1674,6 +1674,19 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)die("index file corrupt");}+/*+*Signalthatthesharedindexisusedbyupdatingitsmtime.+*+*Thisway,sharedindexcanberemovediftheyhavenotbeenused+*forsometime.+*/+staticvoidfreshen_shared_index(char*base_sha1_hex,intwarn)+{+constchar*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);+}+intread_index_from(structindex_state*istate,constchar*path){structsplit_index*split_index;
@@ -2245,6 +2258,7 @@ static int too_many_not_shared_entries(struct index_state *istate)intwrite_locked_index(structindex_state*istate,structlock_file*lock,unsignedflags){+intnew_shared_index,ret;structsplit_index*si=istate->split_index;if(!si||alternate_index_output||
@@ -2261,13 +2275,22 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,}if(too_many_not_shared_entries(istate))istate->cache_changed|=SPLIT_INDEX_ORDERED;-if(istate->cache_changed&SPLIT_INDEX_ORDERED){-intret=write_shared_index(istate,lock,flags);++new_shared_index=istate->cache_changed&SPLIT_INDEX_ORDERED;++if(new_shared_index){+ret=write_shared_index(istate,lock,flags);if(ret)returnret;}-returnwrite_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);++returnret;}/*
From: Christian Couder <hidden> Date: 2017-02-27 18:59:27
Everytime split index is turned on, it creates a "sharedindex.XXXX"
file in the git directory. This change makes sure that shared index
files that haven't been used for a long time are removed when a new
shared index file is created.
The new "splitIndex.sharedIndexExpire" config variable is created
to tell the delay after which an unused shared index file can be
deleted. It defaults to "2.weeks.ago".
A previous commit made sure that each time a split index file is
created the mtime of the shared index file it references is updated.
This makes sure that recently used shared index file will not be
deleted.
Signed-off-by: Christian Couder <redacted>
---
read-cache.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 63 insertions(+), 1 deletion(-)
@@ -2199,6 +2199,65 @@ static int write_split_index(struct index_state *istate,returnret;}+staticconstchar*shared_index_expire="2.weeks.ago";++staticunsignedlongget_shared_index_expire_date(void)+{+staticunsignedlongshared_index_expire_date;+staticintshared_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;+}++returnshared_index_expire_date;+}++staticintcan_delete_shared_index(constchar*shared_index_path)+{+structstatst;+unsignedlongexpiration;++/* Check timestamp */+expiration=get_shared_index_expire_date();+if(!expiration)+return0;+if(stat(shared_index_path,&st))+returnerror_errno(_("could not stat '%s"),shared_index_path);+if(st.st_mtime>expiration)+return0;++return1;+}++staticintclean_shared_index_files(constchar*current_hex)+{+structdirent*de;+DIR*dir=opendir(get_git_dir());++if(!dir)+returnerror_errno(_("unable to open git dir: %s"),get_git_dir());++while((de=readdir(dir))!=NULL){+constchar*sha1_hex;+constchar*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(can_delete_shared_index(shared_index_path)>0&&+unlink(shared_index_path))+error_errno(_("unable to unlink: %s"),shared_index_path);+}+closedir(dir);++return0;+}+staticstructtempfiletemporary_sharedindex;staticintwrite_shared_index(structindex_state*istate,
@@ -2220,8 +2279,11 @@ 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));+}+returnret;}
@@ -2844,6 +2844,18 @@ splitIndex.maxPercentChange:: than 20 percent of the total number of entries. See linkgit:git-update-index[1].+splitIndex.sharedIndexExpire::+ When the split index feature is used, shared index files that+ were not modified since the time this variable specifies will+ be removed when a new shared index file is created. The value+ "now" expires all entries immediately, and "never" suppresses+ expiration altogether.+ The default value is "2.weeks.ago".+ Note that a shared index file is considered modified (for the+ purpose of expiration) each time a new split-index file is+ created based on it.+ See linkgit:git-update-index[1].+ status.relativePaths:: By default, linkgit:git-status[1] shows paths relative to the current directory. Setting this variable to `false` shows paths