git

Форк
0
/
pseudo-merge.c 
765 строк · 19.7 Кб
1
#define USE_THE_REPOSITORY_VARIABLE
2

3
#include "git-compat-util.h"
4
#include "pseudo-merge.h"
5
#include "date.h"
6
#include "oid-array.h"
7
#include "strbuf.h"
8
#include "config.h"
9
#include "string-list.h"
10
#include "refs.h"
11
#include "pack-bitmap.h"
12
#include "commit.h"
13
#include "alloc.h"
14
#include "progress.h"
15
#include "hex.h"
16

17
#define DEFAULT_PSEUDO_MERGE_DECAY 1.0
18
#define DEFAULT_PSEUDO_MERGE_MAX_MERGES 64
19
#define DEFAULT_PSEUDO_MERGE_SAMPLE_RATE 1
20
#define DEFAULT_PSEUDO_MERGE_THRESHOLD approxidate("1.week.ago")
21
#define DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD approxidate("1.month.ago")
22
#define DEFAULT_PSEUDO_MERGE_STABLE_SIZE 512
23

24
static double gitexp(double base, int exp)
25
{
26
	double result = 1;
27
	while (1) {
28
		if (exp % 2)
29
			result *= base;
30
		exp >>= 1;
31
		if (!exp)
32
			break;
33
		base *= base;
34
	}
35
	return result;
36
}
37

38
static uint32_t pseudo_merge_group_size(const struct pseudo_merge_group *group,
39
					const struct pseudo_merge_matches *matches,
40
					uint32_t i)
41
{
42
	double C = 0.0f;
43
	uint32_t n;
44

45
	/*
46
	 * The size of pseudo-merge groups decays according to a power series,
47
	 * which looks like:
48
	 *
49
	 *   f(n) = C * n^-k
50
	 *
51
	 * , where 'n' is the n-th pseudo-merge group, 'f(n)' is its size, 'k'
52
	 * is the decay rate, and 'C' is a scaling value.
53
	 *
54
	 * The value of C depends on the number of groups, decay rate, and total
55
	 * number of commits. It is computed such that if there are M and N
56
	 * total groups and commits, respectively, that:
57
	 *
58
	 *   N = f(0) + f(1) + ... f(M-1)
59
	 *
60
	 * Rearranging to isolate C, we get:
61
	 *
62
	 *   N = \sum_{n=1}^M C / n^k
63
	 *
64
	 *   N / C = \sum_{n=1}^M n^-k
65
	 *
66
	 *   C = N / \sum_{n=1}^M n^-k
67
	 *
68
	 * For example, if we have a decay rate of 'k' being equal to 1.5, 'N'
69
	 * total commits equal to 10,000, and 'M' being equal to 6 groups, then
70
	 * the (rounded) group sizes are:
71
	 *
72
	 *   { 5469, 1934, 1053, 684, 489, 372 }
73
	 *
74
	 * increasing the number of total groups, say to 10, scales the group
75
	 * sizes appropriately:
76
	 *
77
	 *   { 5012, 1772, 964, 626, 448, 341, 271, 221, 186, 158 }
78
	 */
79
	for (n = 0; n < group->max_merges; n++)
80
		C += 1.0 / gitexp(n + 1, group->decay);
81
	C = matches->unstable_nr / C;
82

83
	return (uint32_t)((C / gitexp(i + 1, group->decay)) + 0.5);
84
}
85

86
static void pseudo_merge_group_init(struct pseudo_merge_group *group)
87
{
88
	memset(group, 0, sizeof(struct pseudo_merge_group));
89

90
	strmap_init_with_options(&group->matches, NULL, 0);
91

92
	group->decay = DEFAULT_PSEUDO_MERGE_DECAY;
93
	group->max_merges = DEFAULT_PSEUDO_MERGE_MAX_MERGES;
94
	group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
95
	group->threshold = DEFAULT_PSEUDO_MERGE_THRESHOLD;
96
	group->stable_threshold = DEFAULT_PSEUDO_MERGE_STABLE_THRESHOLD;
97
	group->stable_size = DEFAULT_PSEUDO_MERGE_STABLE_SIZE;
98
}
99

100
static int pseudo_merge_config(const char *var, const char *value,
101
			       const struct config_context *ctx,
102
			       void *cb_data)
103
{
104
	struct string_list *list = cb_data;
105
	struct string_list_item *item;
106
	struct pseudo_merge_group *group;
107
	struct strbuf buf = STRBUF_INIT;
108
	const char *sub, *key;
109
	size_t sub_len;
110
	int ret = 0;
111

112
	if (parse_config_key(var, "bitmappseudomerge", &sub, &sub_len, &key))
113
		goto done;
114

115
	if (!sub_len)
116
		goto done;
117

118
	strbuf_add(&buf, sub, sub_len);
119

120
	item = string_list_lookup(list, buf.buf);
121
	if (!item) {
122
		item = string_list_insert(list, buf.buf);
123

124
		item->util = xmalloc(sizeof(struct pseudo_merge_group));
125
		pseudo_merge_group_init(item->util);
126
	}
127

128
	group = item->util;
129

130
	if (!strcmp(key, "pattern")) {
131
		struct strbuf re = STRBUF_INIT;
132

133
		free(group->pattern);
134
		if (*value != '^')
135
			strbuf_addch(&re, '^');
136
		strbuf_addstr(&re, value);
137

138
		group->pattern = xcalloc(1, sizeof(regex_t));
139
		if (regcomp(group->pattern, re.buf, REG_EXTENDED))
140
			die(_("failed to load pseudo-merge regex for %s: '%s'"),
141
			    sub, re.buf);
142

143
		strbuf_release(&re);
144
	} else if (!strcmp(key, "decay")) {
145
		group->decay = git_config_double(var, value, ctx->kvi);
146
		if (group->decay < 0) {
147
			warning(_("%s must be non-negative, using default"), var);
148
			group->decay = DEFAULT_PSEUDO_MERGE_DECAY;
149
		}
150
	} else if (!strcmp(key, "samplerate")) {
151
		group->sample_rate = git_config_double(var, value, ctx->kvi);
152
		if (!(0 <= group->sample_rate && group->sample_rate <= 1)) {
153
			warning(_("%s must be between 0 and 1, using default"), var);
154
			group->sample_rate = DEFAULT_PSEUDO_MERGE_SAMPLE_RATE;
155
		}
156
	} else if (!strcmp(key, "threshold")) {
157
		if (git_config_expiry_date(&group->threshold, var, value)) {
158
			ret = -1;
159
			goto done;
160
		}
161
	} else if (!strcmp(key, "maxmerges")) {
162
		group->max_merges = git_config_int(var, value, ctx->kvi);
163
		if (group->max_merges < 0) {
164
			warning(_("%s must be non-negative, using default"), var);
165
			group->max_merges = DEFAULT_PSEUDO_MERGE_MAX_MERGES;
166
		}
167
	} else if (!strcmp(key, "stablethreshold")) {
168
		if (git_config_expiry_date(&group->stable_threshold, var, value)) {
169
			ret = -1;
170
			goto done;
171
		}
172
	} else if (!strcmp(key, "stablesize")) {
173
		group->stable_size = git_config_int(var, value, ctx->kvi);
174
		if (group->stable_size <= 0) {
175
			warning(_("%s must be positive, using default"), var);
176
			group->stable_size = DEFAULT_PSEUDO_MERGE_STABLE_SIZE;
177
		}
178
	}
179

180
done:
181
	strbuf_release(&buf);
182

183
	return ret;
184
}
185

186
void load_pseudo_merges_from_config(struct repository *r,
187
				    struct string_list *list)
188
{
189
	struct string_list_item *item;
190

191
	repo_config(r, pseudo_merge_config, list);
192

193
	for_each_string_list_item(item, list) {
194
		struct pseudo_merge_group *group = item->util;
195
		if (!group->pattern)
196
			die(_("pseudo-merge group '%s' missing required pattern"),
197
			    item->string);
198
		if (group->threshold < group->stable_threshold)
199
			die(_("pseudo-merge group '%s' has unstable threshold "
200
			      "before stable one"), item->string);
201
	}
202
}
203

204
static int find_pseudo_merge_group_for_ref(const char *refname,
205
					   const char *referent UNUSED,
206
					   const struct object_id *oid,
207
					   int flags UNUSED,
208
					   void *_data)
209
{
210
	struct bitmap_writer *writer = _data;
211
	struct object_id peeled;
212
	struct commit *c;
213
	uint32_t i;
214
	int has_bitmap;
215

216
	if (!peel_iterated_oid(the_repository, oid, &peeled))
217
		oid = &peeled;
218

219
	c = lookup_commit(the_repository, oid);
220
	if (!c)
221
		return 0;
222
	if (!packlist_find(writer->to_pack, oid))
223
		return 0;
224

225
	has_bitmap = bitmap_writer_has_bitmapped_object_id(writer, oid);
226

227
	for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
228
		struct pseudo_merge_group *group;
229
		struct pseudo_merge_matches *matches;
230
		struct strbuf group_name = STRBUF_INIT;
231
		regmatch_t captures[16];
232
		size_t j;
233

234
		group = writer->pseudo_merge_groups.items[i].util;
235
		if (regexec(group->pattern, refname, ARRAY_SIZE(captures),
236
			    captures, 0))
237
			continue;
238

239
		if (captures[ARRAY_SIZE(captures) - 1].rm_so != -1)
240
			warning(_("pseudo-merge regex from config has too many capture "
241
				  "groups (max=%"PRIuMAX")"),
242
				(uintmax_t)ARRAY_SIZE(captures) - 2);
243

244
		for (j = !!group->pattern->re_nsub; j < ARRAY_SIZE(captures); j++) {
245
			regmatch_t *match = &captures[j];
246
			if (match->rm_so == -1)
247
				continue;
248

249
			if (group_name.len)
250
				strbuf_addch(&group_name, '-');
251

252
			strbuf_add(&group_name, refname + match->rm_so,
253
				   match->rm_eo - match->rm_so);
254
		}
255

256
		matches = strmap_get(&group->matches, group_name.buf);
257
		if (!matches) {
258
			matches = xcalloc(1, sizeof(*matches));
259
			strmap_put(&group->matches, strbuf_detach(&group_name, NULL),
260
				   matches);
261
		}
262

263
		if (c->date <= group->stable_threshold) {
264
			ALLOC_GROW(matches->stable, matches->stable_nr + 1,
265
				   matches->stable_alloc);
266
			matches->stable[matches->stable_nr++] = c;
267
		} else if (c->date <= group->threshold && !has_bitmap) {
268
			ALLOC_GROW(matches->unstable, matches->unstable_nr + 1,
269
				   matches->unstable_alloc);
270
			matches->unstable[matches->unstable_nr++] = c;
271
		}
272

273
		strbuf_release(&group_name);
274
	}
275

276
	return 0;
277
}
278

279
static struct commit *push_pseudo_merge(struct pseudo_merge_group *group)
280
{
281
	struct commit *merge;
282

283
	ALLOC_GROW(group->merges, group->merges_nr + 1, group->merges_alloc);
284

285
	merge = alloc_commit_node(the_repository);
286
	merge->object.parsed = 1;
287
	merge->object.flags |= BITMAP_PSEUDO_MERGE;
288

289
	group->merges[group->merges_nr++] = merge;
290

291
	return merge;
292
}
293

294
static struct pseudo_merge_commit_idx *pseudo_merge_idx(kh_oid_map_t *pseudo_merge_commits,
295
							const struct object_id *oid)
296

297
{
298
	struct pseudo_merge_commit_idx *pmc;
299
	int hash_ret;
300
	khiter_t hash_pos = kh_put_oid_map(pseudo_merge_commits, *oid,
301
					   &hash_ret);
302

303
	if (hash_ret) {
304
		CALLOC_ARRAY(pmc, 1);
305
		kh_value(pseudo_merge_commits, hash_pos) = pmc;
306
	} else {
307
		pmc = kh_value(pseudo_merge_commits, hash_pos);
308
	}
309

310
	return pmc;
311
}
312

313
#define MIN_PSEUDO_MERGE_SIZE 8
314

315
static void select_pseudo_merges_1(struct bitmap_writer *writer,
316
				   struct pseudo_merge_group *group,
317
				   struct pseudo_merge_matches *matches)
318
{
319
	uint32_t i, j;
320
	uint32_t stable_merges_nr;
321

322
	if (!matches->stable_nr && !matches->unstable_nr)
323
		return; /* all tips in this group already have bitmaps */
324

325
	stable_merges_nr = matches->stable_nr / group->stable_size;
326
	if (matches->stable_nr % group->stable_size)
327
		stable_merges_nr++;
328

329
	/* make stable_merges_nr pseudo merges for stable commits */
330
	for (i = 0, j = 0; i < stable_merges_nr; i++) {
331
		struct commit *merge;
332
		struct commit_list **p;
333

334
		merge = push_pseudo_merge(group);
335
		p = &merge->parents;
336

337
		/*
338
		 * For each pseudo-merge created above, add parents to the
339
		 * allocated commit node from the stable set of commits
340
		 * (un-bitmapped, newer than the stable threshold).
341
		 */
342
		do {
343
			struct commit *c;
344
			struct pseudo_merge_commit_idx *pmc;
345

346
			if (j >= matches->stable_nr)
347
				break;
348

349
			c = matches->stable[j++];
350
			/*
351
			 * Here and below, make sure that we keep our mapping of
352
			 * commits -> pseudo-merge(s) which include the key'd
353
			 * commit up-to-date.
354
			 */
355
			pmc = pseudo_merge_idx(writer->pseudo_merge_commits,
356
					       &c->object.oid);
357

358
			ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc);
359

360
			pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr;
361
			p = commit_list_append(c, p);
362
		} while (j % group->stable_size);
363

364
		if (merge->parents) {
365
			bitmap_writer_push_commit(writer, merge, 1);
366
			writer->pseudo_merges_nr++;
367
		}
368
	}
369

370
	/* make up to group->max_merges pseudo merges for unstable commits */
371
	for (i = 0, j = 0; i < group->max_merges; i++) {
372
		struct commit *merge;
373
		struct commit_list **p;
374
		uint32_t size, end;
375

376
		merge = push_pseudo_merge(group);
377
		p = &merge->parents;
378

379
		size = pseudo_merge_group_size(group, matches, i);
380
		end = size < MIN_PSEUDO_MERGE_SIZE ? matches->unstable_nr : j + size;
381

382
		/*
383
		 * For each pseudo-merge commit created above, add parents to
384
		 * the allocated commit node from the unstable set of commits
385
		 * (newer than the stable threshold).
386
		 *
387
		 * Account for the sample rate, since not every candidate from
388
		 * the set of stable commits will be included as a pseudo-merge
389
		 * parent.
390
		 */
391
		for (; j < end && j < matches->unstable_nr; j++) {
392
			struct commit *c = matches->unstable[j];
393
			struct pseudo_merge_commit_idx *pmc;
394

395
			if (j % (uint32_t)(1.0 / group->sample_rate))
396
				continue;
397

398
			pmc = pseudo_merge_idx(writer->pseudo_merge_commits,
399
					       &c->object.oid);
400

401
			ALLOC_GROW(pmc->pseudo_merge, pmc->nr + 1, pmc->alloc);
402

403
			pmc->pseudo_merge[pmc->nr++] = writer->pseudo_merges_nr;
404
			p = commit_list_append(c, p);
405
		}
406

407
		if (merge->parents) {
408
			bitmap_writer_push_commit(writer, merge, 1);
409
			writer->pseudo_merges_nr++; }
410
		if (end >= matches->unstable_nr)
411
			break;
412
	}
413
}
414

415
static int commit_date_cmp(const void *va, const void *vb)
416
{
417
	timestamp_t a = (*(const struct commit **)va)->date;
418
	timestamp_t b = (*(const struct commit **)vb)->date;
419

420
	if (a < b)
421
		return -1;
422
	else if (a > b)
423
		return 1;
424
	return 0;
425
}
426

427
static void sort_pseudo_merge_matches(struct pseudo_merge_matches *matches)
428
{
429
	QSORT(matches->stable, matches->stable_nr, commit_date_cmp);
430
	QSORT(matches->unstable, matches->unstable_nr, commit_date_cmp);
431
}
432

433
void select_pseudo_merges(struct bitmap_writer *writer)
434
{
435
	struct progress *progress = NULL;
436
	uint32_t i;
437

438
	if (!writer->pseudo_merge_groups.nr)
439
		return;
440

441
	if (writer->show_progress)
442
		progress = start_progress("Selecting pseudo-merge commits",
443
					  writer->pseudo_merge_groups.nr);
444

445
	refs_for_each_ref(get_main_ref_store(the_repository),
446
			  find_pseudo_merge_group_for_ref, writer);
447

448
	for (i = 0; i < writer->pseudo_merge_groups.nr; i++) {
449
		struct pseudo_merge_group *group;
450
		struct hashmap_iter iter;
451
		struct strmap_entry *e;
452

453
		group = writer->pseudo_merge_groups.items[i].util;
454
		strmap_for_each_entry(&group->matches, &iter, e) {
455
			struct pseudo_merge_matches *matches = e->value;
456

457
			sort_pseudo_merge_matches(matches);
458

459
			select_pseudo_merges_1(writer, group, matches);
460
		}
461

462
		display_progress(progress, i + 1);
463
	}
464

465
	stop_progress(&progress);
466
}
467

468
void free_pseudo_merge_map(struct pseudo_merge_map *pm)
469
{
470
	uint32_t i;
471
	for (i = 0; i < pm->nr; i++) {
472
		ewah_pool_free(pm->v[i].commits);
473
		ewah_pool_free(pm->v[i].bitmap);
474
	}
475
	free(pm->v);
476
}
477

478
struct pseudo_merge_commit_ext {
479
	uint32_t nr;
480
	const unsigned char *ptr;
481
};
482

483
static int pseudo_merge_ext_at(const struct pseudo_merge_map *pm,
484
			       struct pseudo_merge_commit_ext *ext, size_t at)
485
{
486
	if (at >= pm->map_size)
487
		return error(_("extended pseudo-merge read out-of-bounds "
488
			       "(%"PRIuMAX" >= %"PRIuMAX")"),
489
			     (uintmax_t)at, (uintmax_t)pm->map_size);
490
	if (at + 4 >= pm->map_size)
491
		return error(_("extended pseudo-merge entry is too short "
492
			       "(%"PRIuMAX" >= %"PRIuMAX")"),
493
			     (uintmax_t)(at + 4), (uintmax_t)pm->map_size);
494

495
	ext->nr = get_be32(pm->map + at);
496
	ext->ptr = pm->map + at + sizeof(uint32_t);
497

498
	return 0;
499
}
500

501
struct ewah_bitmap *pseudo_merge_bitmap(const struct pseudo_merge_map *pm,
502
					struct pseudo_merge *merge)
503
{
504
	if (!merge->loaded_commits)
505
		BUG("cannot use unloaded pseudo-merge bitmap");
506

507
	if (!merge->loaded_bitmap) {
508
		size_t at = merge->bitmap_at;
509

510
		merge->bitmap = read_bitmap(pm->map, pm->map_size, &at);
511
		merge->loaded_bitmap = 1;
512
	}
513

514
	return merge->bitmap;
515
}
516

517
struct pseudo_merge *use_pseudo_merge(const struct pseudo_merge_map *pm,
518
				      struct pseudo_merge *merge)
519
{
520
	if (!merge->loaded_commits) {
521
		size_t pos = merge->at;
522

523
		merge->commits = read_bitmap(pm->map, pm->map_size, &pos);
524
		merge->bitmap_at = pos;
525
		merge->loaded_commits = 1;
526
	}
527
	return merge;
528
}
529

530
static struct pseudo_merge *pseudo_merge_at(const struct pseudo_merge_map *pm,
531
					    struct object_id *oid,
532
					    size_t want)
533
{
534
	size_t lo = 0;
535
	size_t hi = pm->nr;
536

537
	while (lo < hi) {
538
		size_t mi = lo + (hi - lo) / 2;
539
		size_t got = pm->v[mi].at;
540

541
		if (got == want)
542
			return use_pseudo_merge(pm, &pm->v[mi]);
543
		else if (got < want)
544
			hi = mi;
545
		else
546
			lo = mi + 1;
547
	}
548

549
	warning(_("could not find pseudo-merge for commit %s at offset %"PRIuMAX),
550
		oid_to_hex(oid), (uintmax_t)want);
551

552
	return NULL;
553
}
554

555
struct pseudo_merge_commit {
556
	uint32_t commit_pos;
557
	uint64_t pseudo_merge_ofs;
558
};
559

560
#define PSEUDO_MERGE_COMMIT_RAWSZ (sizeof(uint32_t)+sizeof(uint64_t))
561

562
static void read_pseudo_merge_commit_at(struct pseudo_merge_commit *merge,
563
					const unsigned char *at)
564
{
565
	merge->commit_pos = get_be32(at);
566
	merge->pseudo_merge_ofs = get_be64(at + sizeof(uint32_t));
567
}
568

569
static int nth_pseudo_merge_ext(const struct pseudo_merge_map *pm,
570
				struct pseudo_merge_commit_ext *ext,
571
				struct pseudo_merge_commit *merge,
572
				uint32_t n)
573
{
574
	size_t ofs;
575

576
	if (n >= ext->nr)
577
		return error(_("extended pseudo-merge lookup out-of-bounds "
578
			       "(%"PRIu32" >= %"PRIu32")"), n, ext->nr);
579

580
	ofs = get_be64(ext->ptr + st_mult(n, sizeof(uint64_t)));
581
	if (ofs >= pm->map_size)
582
		return error(_("out-of-bounds read: (%"PRIuMAX" >= %"PRIuMAX")"),
583
			     (uintmax_t)ofs, (uintmax_t)pm->map_size);
584

585
	read_pseudo_merge_commit_at(merge, pm->map + ofs);
586

587
	return 0;
588
}
589

590
static unsigned apply_pseudo_merge(const struct pseudo_merge_map *pm,
591
				   struct pseudo_merge *merge,
592
				   struct bitmap *result,
593
				   struct bitmap *roots)
594
{
595
	if (merge->satisfied)
596
		return 0;
597

598
	if (!ewah_bitmap_is_subset(merge->commits, roots ? roots : result))
599
		return 0;
600

601
	bitmap_or_ewah(result, pseudo_merge_bitmap(pm, merge));
602
	if (roots)
603
		bitmap_or_ewah(roots, pseudo_merge_bitmap(pm, merge));
604
	merge->satisfied = 1;
605

606
	return 1;
607
}
608

609
static int pseudo_merge_commit_cmp(const void *va, const void *vb)
610
{
611
	struct pseudo_merge_commit merge;
612
	uint32_t key = *(uint32_t*)va;
613

614
	read_pseudo_merge_commit_at(&merge, vb);
615

616
	if (key < merge.commit_pos)
617
		return -1;
618
	if (key > merge.commit_pos)
619
		return 1;
620
	return 0;
621
}
622

623
static struct pseudo_merge_commit *find_pseudo_merge(const struct pseudo_merge_map *pm,
624
						     uint32_t pos)
625
{
626
	if (!pm->commits_nr)
627
		return NULL;
628

629
	return bsearch(&pos, pm->commits, pm->commits_nr,
630
		       PSEUDO_MERGE_COMMIT_RAWSZ, pseudo_merge_commit_cmp);
631
}
632

633
int apply_pseudo_merges_for_commit(const struct pseudo_merge_map *pm,
634
				   struct bitmap *result,
635
				   struct commit *commit, uint32_t commit_pos)
636
{
637
	struct pseudo_merge *merge;
638
	struct pseudo_merge_commit *merge_commit;
639
	int ret = 0;
640

641
	merge_commit = find_pseudo_merge(pm, commit_pos);
642
	if (!merge_commit)
643
		return 0;
644

645
	if (merge_commit->pseudo_merge_ofs & ((uint64_t)1<<63)) {
646
		struct pseudo_merge_commit_ext ext = { 0 };
647
		off_t ofs = merge_commit->pseudo_merge_ofs & ~((uint64_t)1<<63);
648
		uint32_t i;
649

650
		if (pseudo_merge_ext_at(pm, &ext, ofs) < -1) {
651
			warning(_("could not read extended pseudo-merge table "
652
				  "for commit %s"),
653
				oid_to_hex(&commit->object.oid));
654
			return ret;
655
		}
656

657
		for (i = 0; i < ext.nr; i++) {
658
			if (nth_pseudo_merge_ext(pm, &ext, merge_commit, i) < 0)
659
				return ret;
660

661
			merge = pseudo_merge_at(pm, &commit->object.oid,
662
						merge_commit->pseudo_merge_ofs);
663

664
			if (!merge)
665
				return ret;
666

667
			if (apply_pseudo_merge(pm, merge, result, NULL))
668
				ret++;
669
		}
670
	} else {
671
		merge = pseudo_merge_at(pm, &commit->object.oid,
672
					merge_commit->pseudo_merge_ofs);
673

674
		if (!merge)
675
			return ret;
676

677
		if (apply_pseudo_merge(pm, merge, result, NULL))
678
			ret++;
679
	}
680

681
	if (ret)
682
		cascade_pseudo_merges(pm, result, NULL);
683

684
	return ret;
685
}
686

687
int cascade_pseudo_merges(const struct pseudo_merge_map *pm,
688
			  struct bitmap *result,
689
			  struct bitmap *roots)
690
{
691
	unsigned any_satisfied;
692
	int ret = 0;
693

694
	do {
695
		struct pseudo_merge *merge;
696
		uint32_t i;
697

698
		any_satisfied = 0;
699

700
		for (i = 0; i < pm->nr; i++) {
701
			merge = use_pseudo_merge(pm, &pm->v[i]);
702
			if (apply_pseudo_merge(pm, merge, result, roots)) {
703
				any_satisfied |= 1;
704
				ret++;
705
			}
706
		}
707
	} while (any_satisfied);
708

709
	return ret;
710
}
711

712
struct pseudo_merge *pseudo_merge_for_parents(const struct pseudo_merge_map *pm,
713
					      struct bitmap *parents)
714
{
715
	struct pseudo_merge *match = NULL;
716
	size_t i;
717

718
	if (!pm->nr)
719
		return NULL;
720

721
	/*
722
	 * NOTE: this loop is quadratic in the worst-case (where no
723
	 * matching pseudo-merge bitmaps are found), but in practice
724
	 * this is OK for a few reasons:
725
	 *
726
	 *   - Rejecting pseudo-merge bitmaps that do not match the
727
	 *     given commit is done quickly (i.e. `bitmap_equals_ewah()`
728
	 *     returns early when we know the two bitmaps aren't equal.
729
	 *
730
	 *   - Already matched pseudo-merge bitmaps (which we track with
731
	 *     the `->satisfied` bit here) are skipped as potential
732
	 *     candidates.
733
	 *
734
	 *   - The number of pseudo-merges should be small (in the
735
	 *     hundreds for most repositories).
736
	 *
737
	 * If in the future this semi-quadratic behavior does become a
738
	 * problem, another approach would be to keep track of which
739
	 * pseudo-merges are still "viable" after enumerating the
740
	 * pseudo-merge commit's parents:
741
	 *
742
	 *   - A pseudo-merge bitmap becomes non-viable when the bit(s)
743
	 *     corresponding to one or more parent(s) of the given
744
	 *     commit are not set in a candidate pseudo-merge's commits
745
	 *     bitmap.
746
	 *
747
	 *   - After processing all bits, enumerate the remaining set of
748
	 *     viable pseudo-merge bitmaps, and check that their
749
	 *     popcount() matches the number of parents in the given
750
	 *     commit.
751
	 */
752
	for (i = 0; i < pm->nr; i++) {
753
		struct pseudo_merge *candidate = use_pseudo_merge(pm, &pm->v[i]);
754
		if (!candidate || candidate->satisfied)
755
			continue;
756
		if (!bitmap_equals_ewah(parents, candidate->commits))
757
			continue;
758

759
		match = candidate;
760
		match->satisfied = 1;
761
		break;
762
	}
763

764
	return match;
765
}
766

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.