Skip to content

Commit e8ffd03

Browse files
szedergitster
authored andcommitted
read-cache: fix GIT_TEST_SPLIT_INDEX
Running tests with GIT_TEST_SPLIT_INDEX=1 is supposed to turn on the split index feature and trigger index splitting (mostly) randomly. Alas, this has been broken since 6e37c8e (read-cache.c: fix writing "link" index ext with null base oid, 2019-02-13), and GIT_TEST_SPLIT_INDEX=1 hasn't triggered any index splitting since then. This patch makes GIT_TEST_SPLIT_INDEX work again, though it doesn't restore the pre-6e37c8ed3c behavior. To understand the bug, the fix, and the behavior change we first have to look at how GIT_TEST_SPLIT_INDEX used to work before 6e37c8e: There are two places where we check the value of GIT_TEST_SPLIT_INDEX, and before 6e37c8e they worked like this: 1) In the lower-level do_write_index(), where, if GIT_TEST_SPLIT_INDEX is enabled, we call init_split_index(). This call merely allocates and zero-initializes 'istate->split_index', but does nothing else (i.e. doesn't fill the base/shared index with cache entries, doesn't actually write a shared index file, etc.). Pertinent to this issue, the hash of the base index remains all zeroed out. 2) In the higher-level write_locked_index(), but only when 'istate->split_index' has already been initialized. Then, if GIT_TEST_SPLIT_INDEX is enabled, it randomly sets the flag that triggers index splitting later in this function. This randomness comes from the first byte of the hash of the base index via an 'if ((first_byte & 15) < 6)' condition. However, if 'istate->split_index' hasn't been initialized (i.e. it is still NULL), then write_locked_index() just calls do_write_locked_index(), which internally calls the above mentioned do_write_index(). This means that while GIT_TEST_SPLIT_INDEX=1 usually triggered index splitting randomly, the first two index writes were always deterministic (though I suspect this was unintentional): - The initial index write never splits the index. During the first index write write_locked_index() is called with 'istate->split_index' still uninitialized, so the check in 2) is not executed. It still calls do_write_index(), though, which then executes the check in 1). The resulting all zero base index hash then leads to the 'link' extension being written to '.git/index', though a shared index file is not written: $ rm .git/index $ GIT_TEST_SPLIT_INDEX=1 git update-index --add file $ test-tool dump-split-index .git/index own c6ef71168597caec8553c83d9d0048f1ef416170 base 0000000000000000000000000000000000000000 100644 d00491f 0 file replacements: deletions: $ ls -l .git/sharedindex.* ls: cannot access '.git/sharedindex.*': No such file or directory - The second index write always splits the index. When the index written in the previous point is read, 'istate->split_index' is initialized because of the presence of the 'link' extension. So during the second write write_locked_index() does run the check in 2), and the first byte of the all zero base index hash always fulfills the randomness condition, which in turn always triggers the index splitting. - Subsequent index writes will find the 'link' extension with a real non-zero base index hash, so from then on the check in 2) is executed and the first byte of the base index hash is as random as it gets (coming from the SHA-1 of index data including timestamps and inodes...). All this worked until 6e37c8e came along, and stopped writing the 'link' extension if the hash of the base index was all zero: $ rm .git/index $ GIT_TEST_SPLIT_INDEX=1 git update-index --add file $ test-tool dump-split-index .git/index own abbd6f6458d5dee73ae8e210ca15a68a390c6fd7 not a split index $ ls -l .git/sharedindex.* ls: cannot access '.git/sharedindex.*': No such file or directory So, since the first index write with GIT_TEST_SPLIT_INDEX=1 doesn't write a 'link' extension, in the second index write 'istate->split_index' remains uninitialized, and the check in 2) is not executed, and ultimately the index is never split. Fix this by modifying write_locked_index() to make sure to check GIT_TEST_SPLIT_INDEX even if 'istate->split_index' is still uninitialized, and initialize it if necessary. The check for GIT_TEST_SPLIT_INDEX and separate init_split_index() call in do_write_index() thus becomes unnecessary, so remove it. Furthermore, add a test to 't1700-split-index.sh' to make sure that GIT_TEST_SPLIT_INDEX=1 will keep working (though only check the index splitting on the first index write, because after that it will be random). Note that this change does not restore the pre-6e37c8ed3c behaviour, as it will deterministically split the index already on the first index write. Since GIT_TEST_SPLIT_INDEX is purely a developer aid, there is no backwards compatibility issue here. The new behaviour did trigger test failures in 't0003-attributes.sh' and 't1600-index.sh', though, which have been fixed in preparatory patches in this series. Signed-off-by: SZEDER Gábor <[email protected]> Acked-by: Derrick Stolee <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 61feddc commit e8ffd03

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
lines changed

read-cache.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2824,11 +2824,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
28242824
}
28252825
}
28262826

2827-
if (!istate->version) {
2827+
if (!istate->version)
28282828
istate->version = get_index_format_default(the_repository);
2829-
if (git_env_bool("GIT_TEST_SPLIT_INDEX", 0))
2830-
init_split_index(istate);
2831-
}
28322829

28332830
/* demote version 3 to version 2 when the latter suffices */
28342831
if (istate->version == 3 || istate->version == 2)
@@ -3255,7 +3252,7 @@ static int too_many_not_shared_entries(struct index_state *istate)
32553252
int write_locked_index(struct index_state *istate, struct lock_file *lock,
32563253
unsigned flags)
32573254
{
3258-
int new_shared_index, ret;
3255+
int new_shared_index, ret, test_split_index_env;
32593256
struct split_index *si = istate->split_index;
32603257

32613258
if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
@@ -3270,18 +3267,26 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
32703267
if (istate->fsmonitor_last_update)
32713268
fill_fsmonitor_bitmap(istate);
32723269

3273-
if (!si || alternate_index_output ||
3270+
test_split_index_env = git_env_bool("GIT_TEST_SPLIT_INDEX", 0);
3271+
3272+
if ((!si && !test_split_index_env) ||
3273+
alternate_index_output ||
32743274
(istate->cache_changed & ~EXTMASK)) {
32753275
if (si)
32763276
oidclr(&si->base_oid);
32773277
ret = do_write_locked_index(istate, lock, flags);
32783278
goto out;
32793279
}
32803280

3281-
if (git_env_bool("GIT_TEST_SPLIT_INDEX", 0)) {
3282-
int v = si->base_oid.hash[0];
3283-
if ((v & 15) < 6)
3281+
if (test_split_index_env) {
3282+
if (!si) {
3283+
si = init_split_index(istate);
32843284
istate->cache_changed |= SPLIT_INDEX_ORDERED;
3285+
} else {
3286+
int v = si->base_oid.hash[0];
3287+
if ((v & 15) < 6)
3288+
istate->cache_changed |= SPLIT_INDEX_ORDERED;
3289+
}
32853290
}
32863291
if (too_many_not_shared_entries(istate))
32873292
istate->cache_changed |= SPLIT_INDEX_ORDERED;

t/t1700-split-index.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,4 +533,15 @@ test_expect_success 'reading split index at alternate location' '
533533
test_cmp expect actual
534534
'
535535

536+
test_expect_success 'GIT_TEST_SPLIT_INDEX works' '
537+
git init git-test-split-index &&
538+
(
539+
cd git-test-split-index &&
540+
>file &&
541+
GIT_TEST_SPLIT_INDEX=1 git update-index --add file &&
542+
ls -l .git/sharedindex.* >actual &&
543+
test_line_count = 1 actual
544+
)
545+
'
546+
536547
test_done

0 commit comments

Comments
 (0)