Anonymous avatar Anonymous committed 1c3039e

Make git-pack-redundant consider alt-odbs

This patch changes git-pack-redundant so that packfiles
in alternate object directories also are considered when
deciding which objects are redundant.

This functionality is controlled by the flag '--alt-odb'.

Also convert the other flags to the long form, and update
docs and git-repack accordingly.

Signed-off-by: Lukas Sandström <lukass@etek.chalmers.se>;
Signed-off-by: Junio C Hamano <junkio@cox.net>;

Comments (0)

Files changed (3)

Documentation/git-pack-redundant.txt

 
 SYNOPSIS
 --------
-'git-pack-redundant [ -v ] < -a | .pack filename ... >'
+'git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | .pack filename ... >'
 
 DESCRIPTION
 -----------
 OPTIONS
 -------
 
--v::
-	Verbose. Outputs some statistics to stderr.
-	Has a small performance penalty.
 
--a::
-	All. Processes all the local packs. Any filenames on
-	the commandline are ignored.
+--all::
+	Processes all packs. Any filenames on the commandline are ignored.
+
+--alt-odb::
+	Don't require objects present in packs from alternate object
+	directories to be present in local packs.
+
+--verbose::
+	Outputs some statistics to stderr. Has a small performance penalty.
 
 Author
 ------
 	if test "$remove_redandant" = t ; then
 		echo "Removing redundant packs."
 		sync
-		redundant=$(git-pack-redundant -a)
+		redundant=$(git-pack-redundant --all)
 		if test "$redundant" != "" ; then
 			echo $redundant | xargs rm
 		fi
 if test "$remove_redandant" = t
 then
 	sync
-	redundant=$(git-pack-redundant -a)
+	redundant=$(git-pack-redundant --all)
 	if test "$redundant" != "" ; then
 		echo $redundant | xargs rm
 	fi
 #include "cache.h"
 
 static const char pack_redundant_usage[] =
-"git-pack-redundant [ -v ]  < -a | <.pack filename> ...>";
+"git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
 
-int all = 0, verbose = 0;
+int load_all_packs = 0, verbose = 0, alt_odb = 0;
 
 struct llist_item {
 	struct llist_item *next;
 	struct llist_item *front;
 	struct llist_item *back;
 	size_t size;
-} *all_objects;
+} *all_objects; /* all objects which must be present in local packfiles */
 
 struct pack_list {
 	struct pack_list *next;
 	struct packed_git *pack;
 	struct llist *unique_objects;
 	struct llist *all_objects;
-} *pack_list;
+} *local_packs = NULL, *altodb_packs = NULL;
 
 struct pll {
 	struct pll *next;
 }
 
 /* computes A\B */
-struct llist * llist_sorted_difference(struct llist_item *A,
-				       struct llist_item *B)
+void llist_sorted_difference_inplace(struct llist *A,
+				     struct llist *B)
 {
-	struct llist *ret;
-	llist_init(&ret);
+	struct llist_item *prev, *a, *b, *x;
 
-	while (A != NULL && B != NULL) {
-		int cmp = memcmp(A->sha1, B->sha1, 20);
+	prev = a = A->front;
+	b = B->front;
+
+	while (a != NULL && b != NULL) {
+		int cmp = memcmp(a->sha1, b->sha1, 20);
 		if (!cmp) {
-			A = A->next;
-			B = B->next;
-			continue;
-		}
-		if(cmp > 0) { /* we'll never find this B */
-			B = B->next;
-			continue;
-		}
-		/* A has the object, B doesn't */
-		llist_insert_back(ret, A->sha1);
-		A = A->next;
-	}
-	while (A != NULL) {
-		llist_insert_back(ret, A->sha1);
-		A = A->next;
+			x = a;
+			if (a == A->front)
+				A->front = a->next;
+			a = prev->next = a->next;
+
+			if (a == NULL) /* end of list */
+				A->back = prev;
+			A->size--;
+			free(x);
+			b = b->next;
+		} else
+			if (cmp > 0)
+				b = b->next;
+			else {
+				prev = a;
+				a = a->next;
+			}
 	}
-	return ret;
 }
 
 /* returns a pointer to an item in front of sha1 */
 	return p;
 }
 
+inline size_t pack_list_size(struct pack_list *pl)
+{
+	size_t ret = 0;
+	while(pl) {
+		ret++;
+		pl = pl->next;
+	}
+	return ret;
+}
+
 struct pack_list * pack_list_difference(struct pack_list *A,
 					struct pack_list *B)
 {
 
 int is_superset(struct pack_list *pl, struct llist *list)
 {
-	struct llist *diff, *old;
+	struct llist *diff;
 
 	diff = llist_copy(list);
 
 	while (pl) {
-		old = diff;
-		diff = llist_sorted_difference(diff->front,
-					       pl->all_objects->front);
-		llist_free(old);
+		llist_sorted_difference_inplace(diff,
+						pl->all_objects);
 		if (diff->size == 0) { /* we're done */
 			llist_free(diff);
 			return 1;
 size_t get_pack_redundancy(struct pack_list *pl)
 {
 	struct pack_list *subset;
+
+	if (pl == NULL)
+		return 0;
+
 	size_t ret = 0;
 	while ((subset = pl->next)) {
 		while(subset) {
 	struct pack_list *pl, *unique = NULL,
 		*non_unique = NULL, *min_perm = NULL;
 	struct pll *perm, *perm_all, *perm_ok = NULL, *new_perm;
-	struct llist *missing, *old;
+	struct llist *missing;
 	size_t min_perm_size = (size_t)-1, perm_size;
 
-	pl = pack_list;
+	pl = local_packs;
 	while (pl) {
 		if(pl->unique_objects->size)
 			pack_list_insert(&unique, pl);
 	missing = llist_copy(all_objects);
 	pl = unique;
 	while (pl) {
-		old = missing;
-		missing = llist_sorted_difference(missing->front,
-						  pl->all_objects->front);
-		llist_free(old);
+		llist_sorted_difference_inplace(missing,
+						pl->all_objects);
 		pl = pl->next;
 	}
 
+	/* return if there are no objects missing from the unique set */
 	if (missing->size == 0) {
 		*min = unique;
 		return;
 
 void load_all_objects()
 {
-	struct pack_list *pl = pack_list;
+	struct pack_list *pl = local_packs;
 	struct llist_item *hint, *l;
 	int i;
 
 		}
 		pl = pl->next;
 	}
+	/* remove objects present in remote packs */
+	pl = altodb_packs;
+	while (pl) {
+		llist_sorted_difference_inplace(all_objects, pl->all_objects);
+		pl = pl->next;
+	}
 }
 
 /* this scales like O(n^2) */
 void cmp_packs()
 {
-	struct pack_list *subset, *curr = pack_list;
+	struct pack_list *subset, *pl = local_packs;
 
-	while ((subset = curr)) {
+	while ((subset = pl)) {
 		while((subset = subset->next))
-			cmp_two_packs(curr, subset);
-		curr = curr->next;
+			cmp_two_packs(pl, subset);
+		pl = pl->next;
+	}
+
+	pl = altodb_packs;
+	while (pl) {
+		subset = local_packs;
+		while (subset) {
+			llist_sorted_difference_inplace(subset->unique_objects,
+							pl->all_objects);
+			subset = subset->next;
+		}
+		pl = pl->next;
 	}
 }
 
 	}
 	/* this list will be pruned in cmp_two_packs later */
 	l.unique_objects = llist_copy(l.all_objects);
-	return pack_list_insert(&pack_list, &l);
+	if (p->pack_local)
+		return pack_list_insert(&local_packs, &l);
+	else
+		return alt_odb ? pack_list_insert(&altodb_packs, &l) : NULL;
 }
 
 struct pack_list * add_pack_file(char *filename)
 
 	while (p) {
 		if (strstr(p->pack_name, filename))
-			/* this will silently ignore packs in alt-odb */
 			return add_pack(p);
 		p = p->next;
 	}
 	struct packed_git *p = packed_git;
 
 	while (p) {
-		if (p->pack_local) /* ignore alt-odb for now */
-			add_pack(p);
+		add_pack(p);
 		p = p->next;
 	}
 }
 			i++;
 			break;
 		}
-		if(!strcmp(arg, "-a")) {
-			all = 1;
+		if(!strcmp(arg, "--all")) {
+			load_all_packs = 1;
 			continue;
 		}
-		if(!strcmp(arg, "-v")) {
+		if(!strcmp(arg, "--verbose")) {
 			verbose = 1;
 			continue;
 		}
+		if(!strcmp(arg, "--alt-odb")) {
+			alt_odb = 1;
+			continue;
+		}
 		if(*arg == '-')
 			usage(pack_redundant_usage);
 		else
 
 	prepare_packed_git();
 
-	if(all)
+	if (load_all_packs)
 		load_all();
 	else
 		while (*(argv + i) != NULL)
 			add_pack_file(*(argv + i++));
 
-	if (pack_list == NULL)
+	if (local_packs == NULL)
 		die("Zero packs found!\n");
 
 	cmp_packs();
 
 	minimize(&min);
 	if (verbose) {
+		fprintf(stderr, "There are %ld packs available in alt-odbs.\n",
+			pack_list_size(altodb_packs));
 		fprintf(stderr, "The smallest (bytewise) set of packs is:\n");
 		pl = min;
 		while (pl) {
 		fprintf(stderr, "containing %ld duplicate objects "
 				"with a total size of %ldkb.\n",
 			get_pack_redundancy(min), pack_set_bytecount(min)/1024);
+		fprintf(stderr, "A total of %ld unique objects were considered.\n",
+			all_objects->size);
 		fprintf(stderr, "Redundant packs (with indexes):\n");
 	}
-	pl = red = pack_list_difference(pack_list, min);
+	pl = red = pack_list_difference(local_packs, min);
 	while (pl) {
 		printf("%s\n%s\n",
-		       sha1_pack_index_name(pl->pack->sha1), pl->pack->pack_name);
+		       sha1_pack_index_name(pl->pack->sha1),
+		       pl->pack->pack_name);
 		pl = pl->next;
 	}
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.