Skip to content

Commit da165f4

Browse files
committed
unpack-trees.c: prepare for looking ahead in the index
This prepares but does not yet implement a look-ahead in the index entries when traverse-trees.c decides to give us tree entries in an order that does not match what is in the index. A case where a look-ahead in the index is necessary happens when merging branch B into branch A while the index matches the current branch A, using a tree O as their common ancestor, and these three trees looks like this: O A B t t t-i t-i t-i t-j t-j t/1 t/2 The traverse_trees() function gets "t", "t-i" and "t" from trees O, A and B first, and notices that A may have a matching "t" behind "t-i" and "t-j" (indeed it does), and tells A to give that entry instead. After unpacking blob "t" from tree B (as it hasn't changed since O in B and A removed it, it will result in its removal), it descends into directory "t/". The side that walked index in parallel to the tree traversal used to be implemented with one pointer, o->pos, that points at the next index entry to be processed. When this happens, the pointer o->pos still points at "t-i" that is the first entry. We should be able to skip "t-i" and "t-j" and locate "t/1" from the index while the recursive invocation of traverse_trees() walks and match entries found there, and later come back to process "t-i". While that look-ahead is not implemented yet, this adds a flag bit, CE_UNPACKED, to mark the entries in the index that has already been processed. o->pos pointer has been renamed to o->cache_bottom and it points at the first entry that may still need to be processed. Signed-off-by: Junio C Hamano <[email protected]>
1 parent cee2d6a commit da165f4

File tree

4 files changed

+173
-65
lines changed

4 files changed

+173
-65
lines changed

cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ struct cache_entry {
178178
#define CE_HASHED (0x100000)
179179
#define CE_UNHASHED (0x200000)
180180

181+
#define CE_UNPACKED (0x1000000)
182+
181183
/*
182184
* Extended on-disk flags
183185
*/

diff-lib.c

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -359,21 +359,6 @@ static void do_oneway_diff(struct unpack_trees_options *o,
359359
show_modified(revs, tree, idx, 1, cached, match_missing);
360360
}
361361

362-
static inline void skip_same_name(struct cache_entry *ce, struct unpack_trees_options *o)
363-
{
364-
int len = ce_namelen(ce);
365-
const struct index_state *index = o->src_index;
366-
367-
while (o->pos < index->cache_nr) {
368-
struct cache_entry *next = index->cache[o->pos];
369-
if (len != ce_namelen(next))
370-
break;
371-
if (memcmp(ce->name, next->name, len))
372-
break;
373-
o->pos++;
374-
}
375-
}
376-
377362
/*
378363
* The unpack_trees() interface is designed for merging, so
379364
* the different source entries are designed primarily for
@@ -395,9 +380,6 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
395380
struct cache_entry *tree = src[1];
396381
struct rev_info *revs = o->unpack_data;
397382

398-
if (idx && ce_stage(idx))
399-
skip_same_name(idx, o);
400-
401383
/*
402384
* Unpack-trees generates a DF/conflict entry if
403385
* there was a directory in the index and a tree

unpack-trees.c

Lines changed: 170 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,109 @@ static inline int call_unpack_fn(struct cache_entry **src, struct unpack_trees_o
126126
return ret;
127127
}
128128

129-
static int unpack_index_entry(struct cache_entry *ce, struct unpack_trees_options *o)
129+
static void mark_ce_used(struct cache_entry *ce, struct unpack_trees_options *o)
130+
{
131+
ce->ce_flags |= CE_UNPACKED;
132+
133+
if (o->cache_bottom < o->src_index->cache_nr &&
134+
o->src_index->cache[o->cache_bottom] == ce) {
135+
int bottom = o->cache_bottom;
136+
while (bottom < o->src_index->cache_nr &&
137+
o->src_index->cache[bottom]->ce_flags & CE_UNPACKED)
138+
bottom++;
139+
o->cache_bottom = bottom;
140+
}
141+
}
142+
143+
static void mark_all_ce_unused(struct index_state *index)
144+
{
145+
int i;
146+
for (i = 0; i < index->cache_nr; i++)
147+
index->cache[i]->ce_flags &= ~CE_UNPACKED;
148+
}
149+
150+
static int locate_in_src_index(struct cache_entry *ce,
151+
struct unpack_trees_options *o)
152+
{
153+
struct index_state *index = o->src_index;
154+
int len = ce_namelen(ce);
155+
int pos = index_name_pos(index, ce->name, len);
156+
if (pos < 0)
157+
pos = -1 - pos;
158+
return pos;
159+
}
160+
161+
/*
162+
* We call unpack_index_entry() with an unmerged cache entry
163+
* only in diff-index, and it wants a single callback. Skip
164+
* the other unmerged entry with the same name.
165+
*/
166+
static void mark_ce_used_same_name(struct cache_entry *ce,
167+
struct unpack_trees_options *o)
168+
{
169+
struct index_state *index = o->src_index;
170+
int len = ce_namelen(ce);
171+
int pos;
172+
173+
for (pos = locate_in_src_index(ce, o); pos < index->cache_nr; pos++) {
174+
struct cache_entry *next = index->cache[pos];
175+
if (len != ce_namelen(next) ||
176+
memcmp(ce->name, next->name, len))
177+
break;
178+
mark_ce_used(next, o);
179+
}
180+
}
181+
182+
static struct cache_entry *next_cache_entry(struct unpack_trees_options *o)
183+
{
184+
const struct index_state *index = o->src_index;
185+
int pos = o->cache_bottom;
186+
187+
while (pos < index->cache_nr) {
188+
struct cache_entry *ce = index->cache[pos];
189+
if (!(ce->ce_flags & CE_UNPACKED))
190+
return ce;
191+
pos++;
192+
}
193+
return NULL;
194+
}
195+
196+
static void add_same_unmerged(struct cache_entry *ce,
197+
struct unpack_trees_options *o)
198+
{
199+
struct index_state *index = o->src_index;
200+
int len = ce_namelen(ce);
201+
int pos = index_name_pos(index, ce->name, len);
202+
203+
if (0 <= pos)
204+
die("programming error in a caller of mark_ce_used_same_name");
205+
for (pos = -pos - 1; pos < index->cache_nr; pos++) {
206+
struct cache_entry *next = index->cache[pos];
207+
if (len != ce_namelen(next) ||
208+
memcmp(ce->name, next->name, len))
209+
break;
210+
add_entry(o, next, 0, 0);
211+
mark_ce_used(next, o);
212+
}
213+
}
214+
215+
static int unpack_index_entry(struct cache_entry *ce,
216+
struct unpack_trees_options *o)
130217
{
131218
struct cache_entry *src[5] = { ce, NULL, };
219+
int ret;
132220

133-
o->pos++;
221+
mark_ce_used(ce, o);
134222
if (ce_stage(ce)) {
135223
if (o->skip_unmerged) {
136224
add_entry(o, ce, 0, 0);
137225
return 0;
138226
}
139227
}
140-
return call_unpack_fn(src, o);
228+
ret = call_unpack_fn(src, o);
229+
if (ce_stage(ce))
230+
mark_ce_used_same_name(ce, o);
231+
return ret;
141232
}
142233

143234
static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info)
@@ -212,6 +303,20 @@ static int compare_entry(const struct cache_entry *ce, const struct traverse_inf
212303
return ce_namelen(ce) > traverse_path_len(info, n);
213304
}
214305

306+
static int ce_in_traverse_path(const struct cache_entry *ce,
307+
const struct traverse_info *info)
308+
{
309+
if (!info->prev)
310+
return 1;
311+
if (do_compare_entry(ce, info->prev, &info->name))
312+
return 0;
313+
/*
314+
* If ce (blob) is the same name as the path (which is a tree
315+
* we will be descending into), it won't be inside it.
316+
*/
317+
return (info->pathlen < ce_namelen(ce));
318+
}
319+
215320
static struct cache_entry *create_ce_entry(const struct traverse_info *info, const struct name_entry *n, int stage)
216321
{
217322
int len = traverse_path_len(info, n);
@@ -300,23 +405,27 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
300405

301406
/* Are we supposed to look at the index too? */
302407
if (o->merge) {
303-
while (o->pos < o->src_index->cache_nr) {
304-
struct cache_entry *ce = o->src_index->cache[o->pos];
305-
int cmp = compare_entry(ce, info, p);
408+
while (1) {
409+
struct cache_entry *ce = next_cache_entry(o);
410+
int cmp;
411+
if (!ce)
412+
break;
413+
cmp = compare_entry(ce, info, p);
306414
if (cmp < 0) {
307415
if (unpack_index_entry(ce, o) < 0)
308416
return unpack_failed(o, NULL);
309417
continue;
310418
}
311419
if (!cmp) {
312-
o->pos++;
313420
if (ce_stage(ce)) {
314421
/*
315-
* If we skip unmerged index entries, we'll skip this
316-
* entry *and* the tree entries associated with it!
422+
* If we skip unmerged index
423+
* entries, we'll skip this
424+
* entry *and* the tree
425+
* entries associated with it!
317426
*/
318427
if (o->skip_unmerged) {
319-
add_entry(o, ce, 0, 0);
428+
add_same_unmerged(ce, o);
320429
return mask;
321430
}
322431
}
@@ -329,6 +438,13 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
329438
if (unpack_nondirectories(n, mask, dirmask, src, names, info) < 0)
330439
return -1;
331440

441+
if (src[0]) {
442+
if (ce_stage(src[0]))
443+
mark_ce_used_same_name(src[0], o);
444+
else
445+
mark_ce_used(src[0], o);
446+
}
447+
332448
/* Now handle any directories.. */
333449
if (dirmask) {
334450
unsigned long conflicts = mask & ~dirmask;
@@ -345,11 +461,13 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
345461
matches = cache_tree_matches_traversal(o->src_index->cache_tree,
346462
names, info);
347463
/*
348-
* Everything under the name matches. Adjust o->pos to
349-
* skip the entire hierarchy.
464+
* Everything under the name matches; skip the
465+
* entire hierarchy. diff_index_cached codepath
466+
* special cases D/F conflicts in such a way that
467+
* it does not do any look-ahead, so this is safe.
350468
*/
351469
if (matches) {
352-
o->pos += matches;
470+
o->cache_bottom += matches;
353471
return mask;
354472
}
355473
}
@@ -382,11 +500,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
382500

383501
memset(&o->result, 0, sizeof(o->result));
384502
o->result.initialized = 1;
385-
if (o->src_index) {
386-
o->result.timestamp.sec = o->src_index->timestamp.sec;
387-
o->result.timestamp.nsec = o->src_index->timestamp.nsec;
388-
}
503+
o->result.timestamp.sec = o->src_index->timestamp.sec;
504+
o->result.timestamp.nsec = o->src_index->timestamp.nsec;
389505
o->merge_size = len;
506+
mark_all_ce_unused(o->src_index);
390507

391508
if (!dfc)
392509
dfc = xcalloc(1, cache_entry_size(0));
@@ -400,18 +517,38 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
400517
info.fn = unpack_callback;
401518
info.data = o;
402519

520+
if (o->prefix) {
521+
/*
522+
* Unpack existing index entries that sort before the
523+
* prefix the tree is spliced into. Note that o->merge
524+
* is always true in this case.
525+
*/
526+
while (1) {
527+
struct cache_entry *ce = next_cache_entry(o);
528+
if (!ce)
529+
break;
530+
if (ce_in_traverse_path(ce, &info))
531+
break;
532+
if (unpack_index_entry(ce, o) < 0)
533+
goto return_failed;
534+
}
535+
}
536+
403537
if (traverse_trees(len, t, &info) < 0)
404-
return unpack_failed(o, NULL);
538+
goto return_failed;
405539
}
406540

407541
/* Any left-over entries in the index? */
408542
if (o->merge) {
409-
while (o->pos < o->src_index->cache_nr) {
410-
struct cache_entry *ce = o->src_index->cache[o->pos];
543+
while (1) {
544+
struct cache_entry *ce = next_cache_entry(o);
545+
if (!ce)
546+
break;
411547
if (unpack_index_entry(ce, o) < 0)
412-
return unpack_failed(o, NULL);
548+
goto return_failed;
413549
}
414550
}
551+
mark_all_ce_unused(o->src_index);
415552

416553
if (o->trivial_merges_only && o->nontrivial_merge)
417554
return unpack_failed(o, "Merge requires file-level merging");
@@ -421,6 +558,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
421558
if (o->dst_index)
422559
*o->dst_index = o->result;
423560
return ret;
561+
562+
return_failed:
563+
mark_all_ce_unused(o->src_index);
564+
return unpack_failed(o, NULL);
424565
}
425566

426567
/* Here come the merge functions */
@@ -522,20 +663,24 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
522663
* in that directory.
523664
*/
524665
namelen = strlen(ce->name);
525-
for (i = o->pos; i < o->src_index->cache_nr; i++) {
666+
for (i = locate_in_src_index(ce, o);
667+
i < o->src_index->cache_nr;
668+
i++) {
526669
struct cache_entry *ce2 = o->src_index->cache[i];
527670
int len = ce_namelen(ce2);
528671
if (len < namelen ||
529672
strncmp(ce->name, ce2->name, namelen) ||
530673
ce2->name[namelen] != '/')
531674
break;
532675
/*
533-
* ce2->name is an entry in the subdirectory.
676+
* ce2->name is an entry in the subdirectory to be
677+
* removed.
534678
*/
535679
if (!ce_stage(ce2)) {
536680
if (verify_uptodate(ce2, o))
537681
return -1;
538682
add_entry(o, ce2, CE_REMOVE, 0);
683+
mark_ce_used(ce2, o);
539684
}
540685
cnt++;
541686
}
@@ -591,7 +736,6 @@ static int verify_absent(struct cache_entry *ce, const char *action,
591736
return 0;
592737

593738
if (!lstat(ce->name, &st)) {
594-
int ret;
595739
int dtype = ce_to_dtype(ce);
596740
struct cache_entry *result;
597741

@@ -619,28 +763,8 @@ static int verify_absent(struct cache_entry *ce, const char *action,
619763
* files that are in "foo/" we would lose
620764
* them.
621765
*/
622-
ret = verify_clean_subdirectory(ce, action, o);
623-
if (ret < 0)
624-
return ret;
625-
626-
/*
627-
* If this removed entries from the index,
628-
* what that means is:
629-
*
630-
* (1) the caller unpack_callback() saw path/foo
631-
* in the index, and it has not removed it because
632-
* it thinks it is handling 'path' as blob with
633-
* D/F conflict;
634-
* (2) we will return "ok, we placed a merged entry
635-
* in the index" which would cause o->pos to be
636-
* incremented by one;
637-
* (3) however, original o->pos now has 'path/foo'
638-
* marked with "to be removed".
639-
*
640-
* We need to increment it by the number of
641-
* deleted entries here.
642-
*/
643-
o->pos += ret;
766+
if (verify_clean_subdirectory(ce, action, o) < 0)
767+
return -1;
644768
return 0;
645769
}
646770

unpack-trees.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct unpack_trees_options {
3030
diff_index_cached,
3131
gently;
3232
const char *prefix;
33-
int pos;
33+
int cache_bottom;
3434
struct dir_struct *dir;
3535
merge_fn_t fn;
3636
struct unpack_trees_error_msgs msgs;

0 commit comments

Comments
 (0)