Merge branch 'rs/lose-leak-pending' into maint
API clean-up around revision traversal. * rs/lose-leak-pending: commit: remove unused function clear_commit_marks_for_object_array() revision: remove the unused flag leak_pending checkout: avoid using the rev_info flag leak_pending bundle: avoid using the rev_info flag leak_pending bisect: avoid using the rev_info flag leak_pending object: add clear_commit_marks_all() ref-filter: use clear_commit_marks_many() in do_merge_filter() commit: use clear_commit_marks_many() in remove_redundant() commit: avoid allocation in clear_commit_marks_many()maint
						commit
						e17cec27d1
					
				
							
								
								
									
										30
									
								
								bisect.c
								
								
								
								
							
							
						
						
									
										30
									
								
								bisect.c
								
								
								
								
							|  | @ -792,11 +792,9 @@ static void handle_skipped_merge_base(const struct object_id *mb) | ||||||
|  * - If one is "skipped", we can't know but we should warn. |  * - If one is "skipped", we can't know but we should warn. | ||||||
|  * - If we don't know, we should check it out and ask the user to test. |  * - If we don't know, we should check it out and ask the user to test. | ||||||
|  */ |  */ | ||||||
| static void check_merge_bases(int no_checkout) | static void check_merge_bases(int rev_nr, struct commit **rev, int no_checkout) | ||||||
| { | { | ||||||
| 	struct commit_list *result; | 	struct commit_list *result; | ||||||
| 	int rev_nr; |  | ||||||
| 	struct commit **rev = get_bad_and_good_commits(&rev_nr); |  | ||||||
|  |  | ||||||
| 	result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1); | 	result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1); | ||||||
|  |  | ||||||
|  | @ -814,34 +812,21 @@ static void check_merge_bases(int no_checkout) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	free(rev); |  | ||||||
| 	free_commit_list(result); | 	free_commit_list(result); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int check_ancestors(const char *prefix) | static int check_ancestors(int rev_nr, struct commit **rev, const char *prefix) | ||||||
| { | { | ||||||
| 	struct rev_info revs; | 	struct rev_info revs; | ||||||
| 	struct object_array pending_copy; |  | ||||||
| 	int res; | 	int res; | ||||||
|  |  | ||||||
| 	bisect_rev_setup(&revs, prefix, "^%s", "%s", 0); | 	bisect_rev_setup(&revs, prefix, "^%s", "%s", 0); | ||||||
|  |  | ||||||
| 	/* Save pending objects, so they can be cleaned up later. */ |  | ||||||
| 	pending_copy = revs.pending; |  | ||||||
| 	revs.leak_pending = 1; |  | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	 * bisect_common calls prepare_revision_walk right away, which |  | ||||||
| 	 * (together with .leak_pending = 1) makes us the sole owner of |  | ||||||
| 	 * the list of pending objects. |  | ||||||
| 	 */ |  | ||||||
| 	bisect_common(&revs); | 	bisect_common(&revs); | ||||||
| 	res = (revs.commits != NULL); | 	res = (revs.commits != NULL); | ||||||
|  |  | ||||||
| 	/* Clean up objects used, as they will be reused. */ | 	/* Clean up objects used, as they will be reused. */ | ||||||
| 	clear_commit_marks_for_object_array(&pending_copy, ALL_REV_FLAGS); | 	clear_commit_marks_many(rev_nr, rev, ALL_REV_FLAGS); | ||||||
|  |  | ||||||
| 	object_array_clear(&pending_copy); |  | ||||||
|  |  | ||||||
| 	return res; | 	return res; | ||||||
| } | } | ||||||
|  | @ -858,7 +843,8 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout) | ||||||
| { | { | ||||||
| 	char *filename = git_pathdup("BISECT_ANCESTORS_OK"); | 	char *filename = git_pathdup("BISECT_ANCESTORS_OK"); | ||||||
| 	struct stat st; | 	struct stat st; | ||||||
| 	int fd; | 	int fd, rev_nr; | ||||||
|  | 	struct commit **rev; | ||||||
|  |  | ||||||
| 	if (!current_bad_oid) | 	if (!current_bad_oid) | ||||||
| 		die(_("a %s revision is needed"), term_bad); | 		die(_("a %s revision is needed"), term_bad); | ||||||
|  | @ -872,8 +858,10 @@ static void check_good_are_ancestors_of_bad(const char *prefix, int no_checkout) | ||||||
| 		goto done; | 		goto done; | ||||||
|  |  | ||||||
| 	/* Check if all good revs are ancestor of the bad rev. */ | 	/* Check if all good revs are ancestor of the bad rev. */ | ||||||
| 	if (check_ancestors(prefix)) | 	rev = get_bad_and_good_commits(&rev_nr); | ||||||
| 		check_merge_bases(no_checkout); | 	if (check_ancestors(rev_nr, rev, prefix)) | ||||||
|  | 		check_merge_bases(rev_nr, rev, no_checkout); | ||||||
|  | 	free(rev); | ||||||
|  |  | ||||||
| 	/* Create file BISECT_ANCESTORS_OK. */ | 	/* Create file BISECT_ANCESTORS_OK. */ | ||||||
| 	fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600); | 	fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600); | ||||||
|  |  | ||||||
|  | @ -791,7 +791,6 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new) | ||||||
| { | { | ||||||
| 	struct rev_info revs; | 	struct rev_info revs; | ||||||
| 	struct object *object = &old->object; | 	struct object *object = &old->object; | ||||||
| 	struct object_array refs; |  | ||||||
|  |  | ||||||
| 	init_revisions(&revs, NULL); | 	init_revisions(&revs, NULL); | ||||||
| 	setup_revisions(0, NULL, &revs, NULL); | 	setup_revisions(0, NULL, &revs, NULL); | ||||||
|  | @ -802,14 +801,6 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new) | ||||||
| 	for_each_ref(add_pending_uninteresting_ref, &revs); | 	for_each_ref(add_pending_uninteresting_ref, &revs); | ||||||
| 	add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING); | 	add_pending_oid(&revs, "HEAD", &new->object.oid, UNINTERESTING); | ||||||
|  |  | ||||||
| 	/* Save pending objects, so they can be cleaned up later. */ |  | ||||||
| 	refs = revs.pending; |  | ||||||
| 	revs.leak_pending = 1; |  | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	 * prepare_revision_walk (together with .leak_pending = 1) makes us |  | ||||||
| 	 * the sole owner of the list of pending objects. |  | ||||||
| 	 */ |  | ||||||
| 	if (prepare_revision_walk(&revs)) | 	if (prepare_revision_walk(&revs)) | ||||||
| 		die(_("internal error in revision walk")); | 		die(_("internal error in revision walk")); | ||||||
| 	if (!(old->object.flags & UNINTERESTING)) | 	if (!(old->object.flags & UNINTERESTING)) | ||||||
|  | @ -818,9 +809,7 @@ static void orphaned_commit_warning(struct commit *old, struct commit *new) | ||||||
| 		describe_detached_head(_("Previous HEAD position was"), old); | 		describe_detached_head(_("Previous HEAD position was"), old); | ||||||
|  |  | ||||||
| 	/* Clean up objects used, as they will be reused. */ | 	/* Clean up objects used, as they will be reused. */ | ||||||
| 	clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS); | 	clear_commit_marks_all(ALL_REV_FLAGS); | ||||||
|  |  | ||||||
| 	object_array_clear(&refs); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int switch_branches(const struct checkout_opts *opts, | static int switch_branches(const struct checkout_opts *opts, | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								bundle.c
								
								
								
								
							
							
						
						
									
										35
									
								
								bundle.c
								
								
								
								
							|  | @ -134,7 +134,6 @@ int verify_bundle(struct bundle_header *header, int verbose) | ||||||
| 	struct ref_list *p = &header->prerequisites; | 	struct ref_list *p = &header->prerequisites; | ||||||
| 	struct rev_info revs; | 	struct rev_info revs; | ||||||
| 	const char *argv[] = {NULL, "--all", NULL}; | 	const char *argv[] = {NULL, "--all", NULL}; | ||||||
| 	struct object_array refs; |  | ||||||
| 	struct commit *commit; | 	struct commit *commit; | ||||||
| 	int i, ret = 0, req_nr; | 	int i, ret = 0, req_nr; | ||||||
| 	const char *message = _("Repository lacks these prerequisite commits:"); | 	const char *message = _("Repository lacks these prerequisite commits:"); | ||||||
|  | @ -157,14 +156,6 @@ int verify_bundle(struct bundle_header *header, int verbose) | ||||||
| 	req_nr = revs.pending.nr; | 	req_nr = revs.pending.nr; | ||||||
| 	setup_revisions(2, argv, &revs, NULL); | 	setup_revisions(2, argv, &revs, NULL); | ||||||
|  |  | ||||||
| 	/* Save pending objects, so they can be cleaned up later. */ |  | ||||||
| 	refs = revs.pending; |  | ||||||
| 	revs.leak_pending = 1; |  | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	 * prepare_revision_walk (together with .leak_pending = 1) makes us |  | ||||||
| 	 * the sole owner of the list of pending objects. |  | ||||||
| 	 */ |  | ||||||
| 	if (prepare_revision_walk(&revs)) | 	if (prepare_revision_walk(&revs)) | ||||||
| 		die(_("revision walk setup failed")); | 		die(_("revision walk setup failed")); | ||||||
|  |  | ||||||
|  | @ -173,18 +164,24 @@ int verify_bundle(struct bundle_header *header, int verbose) | ||||||
| 		if (commit->object.flags & PREREQ_MARK) | 		if (commit->object.flags & PREREQ_MARK) | ||||||
| 			i--; | 			i--; | ||||||
|  |  | ||||||
| 	for (i = 0; i < req_nr; i++) | 	for (i = 0; i < p->nr; i++) { | ||||||
| 		if (!(refs.objects[i].item->flags & SHOWN)) { | 		struct ref_list_entry *e = p->list + i; | ||||||
| 			if (++ret == 1) | 		struct object *o = parse_object(&e->oid); | ||||||
| 				error("%s", message); | 		assert(o); /* otherwise we'd have returned early */ | ||||||
| 			error("%s %s", oid_to_hex(&refs.objects[i].item->oid), | 		if (o->flags & SHOWN) | ||||||
| 				refs.objects[i].name); | 			continue; | ||||||
| 		} | 		if (++ret == 1) | ||||||
|  | 			error("%s", message); | ||||||
|  | 		error("%s %s", oid_to_hex(&e->oid), e->name); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/* Clean up objects used, as they will be reused. */ | 	/* Clean up objects used, as they will be reused. */ | ||||||
| 	clear_commit_marks_for_object_array(&refs, ALL_REV_FLAGS); | 	for (i = 0; i < p->nr; i++) { | ||||||
|  | 		struct ref_list_entry *e = p->list + i; | ||||||
| 	object_array_clear(&refs); | 		commit = lookup_commit_reference_gently(&e->oid, 1); | ||||||
|  | 		if (commit) | ||||||
|  | 			clear_commit_marks(commit, ALL_REV_FLAGS); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (verbose) { | 	if (verbose) { | ||||||
| 		struct ref_list *r; | 		struct ref_list *r; | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								commit.c
								
								
								
								
							
							
						
						
									
										19
									
								
								commit.c
								
								
								
								
							|  | @ -547,7 +547,7 @@ void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark) | ||||||
| 	struct commit_list *list = NULL; | 	struct commit_list *list = NULL; | ||||||
|  |  | ||||||
| 	while (nr--) { | 	while (nr--) { | ||||||
| 		commit_list_insert(*commit, &list); | 		clear_commit_marks_1(&list, *commit, mark); | ||||||
| 		commit++; | 		commit++; | ||||||
| 	} | 	} | ||||||
| 	while (list) | 	while (list) | ||||||
|  | @ -559,20 +559,6 @@ void clear_commit_marks(struct commit *commit, unsigned int mark) | ||||||
| 	clear_commit_marks_many(1, &commit, mark); | 	clear_commit_marks_many(1, &commit, mark); | ||||||
| } | } | ||||||
|  |  | ||||||
| void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark) |  | ||||||
| { |  | ||||||
| 	struct object *object; |  | ||||||
| 	struct commit *commit; |  | ||||||
| 	unsigned int i; |  | ||||||
|  |  | ||||||
| 	for (i = 0; i < a->nr; i++) { |  | ||||||
| 		object = a->objects[i].item; |  | ||||||
| 		commit = lookup_commit_reference_gently(&object->oid, 1); |  | ||||||
| 		if (commit) |  | ||||||
| 			clear_commit_marks(commit, mark); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| struct commit *pop_commit(struct commit_list **stack) | struct commit *pop_commit(struct commit_list **stack) | ||||||
| { | { | ||||||
| 	struct commit_list *top = *stack; | 	struct commit_list *top = *stack; | ||||||
|  | @ -929,8 +915,7 @@ static int remove_redundant(struct commit **array, int cnt) | ||||||
| 			if (work[j]->object.flags & PARENT1) | 			if (work[j]->object.flags & PARENT1) | ||||||
| 				redundant[filled_index[j]] = 1; | 				redundant[filled_index[j]] = 1; | ||||||
| 		clear_commit_marks(array[i], all_flags); | 		clear_commit_marks(array[i], all_flags); | ||||||
| 		for (j = 0; j < filled; j++) | 		clear_commit_marks_many(filled, work, all_flags); | ||||||
| 			clear_commit_marks(work[j], all_flags); |  | ||||||
| 		free_commit_list(common); | 		free_commit_list(common); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								commit.h
								
								
								
								
							
							
						
						
									
										1
									
								
								commit.h
								
								
								
								
							|  | @ -140,7 +140,6 @@ struct commit *pop_commit(struct commit_list **stack); | ||||||
|  |  | ||||||
| void clear_commit_marks(struct commit *commit, unsigned int mark); | void clear_commit_marks(struct commit *commit, unsigned int mark); | ||||||
| void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark); | void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark); | ||||||
| void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark); |  | ||||||
|  |  | ||||||
|  |  | ||||||
| enum rev_sort_order { | enum rev_sort_order { | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								object.c
								
								
								
								
							
							
						
						
									
										11
									
								
								object.c
								
								
								
								
							|  | @ -434,3 +434,14 @@ void clear_object_flags(unsigned flags) | ||||||
| 			obj->flags &= ~flags; | 			obj->flags &= ~flags; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void clear_commit_marks_all(unsigned int flags) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < obj_hash_size; i++) { | ||||||
|  | 		struct object *obj = obj_hash[i]; | ||||||
|  | 		if (obj && obj->type == OBJ_COMMIT) | ||||||
|  | 			obj->flags &= ~flags; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								object.h
								
								
								
								
							
							
						
						
									
										5
									
								
								object.h
								
								
								
								
							|  | @ -149,4 +149,9 @@ void object_array_clear(struct object_array *array); | ||||||
|  |  | ||||||
| void clear_object_flags(unsigned flags); | void clear_object_flags(unsigned flags); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Clear the specified object flags from all in-core commit objects. | ||||||
|  |  */ | ||||||
|  | extern void clear_commit_marks_all(unsigned int flags); | ||||||
|  |  | ||||||
| #endif /* OBJECT_H */ | #endif /* OBJECT_H */ | ||||||
|  |  | ||||||
|  | @ -1995,8 +1995,7 @@ static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata) | ||||||
| 			free_array_item(item); | 			free_array_item(item); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for (i = 0; i < old_nr; i++) | 	clear_commit_marks_many(old_nr, to_clear, ALL_REV_FLAGS); | ||||||
| 		clear_commit_marks(to_clear[i], ALL_REV_FLAGS); |  | ||||||
| 	clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS); | 	clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS); | ||||||
| 	free(to_clear); | 	free(to_clear); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2862,8 +2862,7 @@ int prepare_revision_walk(struct rev_info *revs) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	if (!revs->leak_pending) | 	object_array_clear(&old_pending); | ||||||
| 		object_array_clear(&old_pending); |  | ||||||
|  |  | ||||||
| 	/* Signal whether we need per-parent treesame decoration */ | 	/* Signal whether we need per-parent treesame decoration */ | ||||||
| 	if (revs->simplify_merges || | 	if (revs->simplify_merges || | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								revision.h
								
								
								
								
							
							
						
						
									
										12
									
								
								revision.h
								
								
								
								
							|  | @ -151,18 +151,6 @@ struct rev_info { | ||||||
| 			date_mode_explicit:1, | 			date_mode_explicit:1, | ||||||
| 			preserve_subject:1; | 			preserve_subject:1; | ||||||
| 	unsigned int	disable_stdin:1; | 	unsigned int	disable_stdin:1; | ||||||
| 	/* |  | ||||||
| 	 * Set `leak_pending` to prevent `prepare_revision_walk()` from clearing |  | ||||||
| 	 * the array of pending objects (`pending`). It will still forget about |  | ||||||
| 	 * the array and its entries, so they really are leaked. This can be |  | ||||||
| 	 * useful if the `struct object_array` `pending` is copied before |  | ||||||
| 	 * calling `prepare_revision_walk()`. By setting `leak_pending`, you |  | ||||||
| 	 * effectively claim ownership of the old array, so you should most |  | ||||||
| 	 * likely call `object_array_clear(&pending_copy)` once you are done. |  | ||||||
| 	 * Observe that this is about ownership of the array and its entries, |  | ||||||
| 	 * not the commits referenced by those entries. |  | ||||||
| 	 */ |  | ||||||
| 	unsigned int	leak_pending:1; |  | ||||||
| 	/* --show-linear-break */ | 	/* --show-linear-break */ | ||||||
| 	unsigned int	track_linear:1, | 	unsigned int	track_linear:1, | ||||||
| 			track_first_time:1, | 			track_first_time:1, | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano