Git development
 help / color / mirror / Atom feed
From: Junio C Hamano <junkio@cox.net>
To: git@vger.kernel.org
Subject: [PATCH 5/6] delete_ref(): delete packed ref
Date: Sat, 30 Sep 2006 15:30:46 -0700	[thread overview]
Message-ID: <7vac4h9ecp.fsf@assigned-by-dhcp.cox.net> (raw)
In-Reply-To: 7v1wptc7ou.fsf@assigned-by-dhcp.cox.net

This implements deletion of a packed ref.  Since it is a very
rare event to delete a ref compared to looking up, creating and
updating, this opts to remove the ref from the packed-ref file
instead of doing any of the filesystem based "negative ref" trick
to optimize the deletion path.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 * This looks larger than it actually is, because it moves delete_ref()
   down so that it can use lock_ref_sha1_basic().

 refs.c |  109 +++++++++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 77 insertions(+), 32 deletions(-)

diff --git a/refs.c b/refs.c
index 2bfa92a..858c534 100644
--- a/refs.c
+++ b/refs.c
@@ -406,33 +406,6 @@ int get_ref_sha1(const char *ref, unsign
 	return read_ref(mkpath("refs/%s", ref), sha1);
 }
 
-int delete_ref(const char *refname, unsigned char *sha1)
-{
-	struct ref_lock *lock;
-	int err, i, ret = 0;
-
-	lock = lock_any_ref_for_update(refname, sha1);
-	if (!lock)
-		return 1;
-	i = strlen(lock->lk->filename) - 5; /* .lock */
-	lock->lk->filename[i] = 0;
-	err = unlink(lock->lk->filename);
-	if (err) {
-		ret = 1;
-		error("unlink(%s) failed: %s",
-		      lock->lk->filename, strerror(errno));
-	}
-	lock->lk->filename[i] = '.';
-
-	err = unlink(lock->log_file);
-	if (err && errno != ENOENT)
-		fprintf(stderr, "warning: unlink(%s) failed: %s",
-			lock->log_file, strerror(errno));
-
-	invalidate_cached_refs();
-	return ret;
-}
-
 /*
  * Make sure "ref" is something reasonable to have under ".git/refs/";
  * We do not like it if:
@@ -555,7 +528,7 @@ static int remove_empty_directories(char
 	return remove_empty_dir_recursive(path, len);
 }
 
-static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char *old_sha1)
+static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char *old_sha1, int *flag)
 {
 	char *ref_file;
 	const char *orig_ref = ref;
@@ -567,7 +540,7 @@ static struct ref_lock *lock_ref_sha1_ba
 	lock = xcalloc(1, sizeof(struct ref_lock));
 	lock->lock_fd = -1;
 
-	ref = resolve_ref(ref, lock->old_sha1, mustexist, NULL);
+	ref = resolve_ref(ref, lock->old_sha1, mustexist, flag);
 	if (!ref && errno == EISDIR) {
 		/* we are trying to lock foo but we used to
 		 * have foo/bar which now does not exist;
@@ -580,7 +553,7 @@ static struct ref_lock *lock_ref_sha1_ba
 			error("there are still refs under '%s'", orig_ref);
 			goto error_return;
 		}
-		ref = resolve_ref(orig_ref, lock->old_sha1, mustexist, NULL);
+		ref = resolve_ref(orig_ref, lock->old_sha1, mustexist, flag);
 	}
 	if (!ref) {
 		last_errno = errno;
@@ -640,12 +613,84 @@ struct ref_lock *lock_ref_sha1(const cha
 	if (check_ref_format(ref))
 		return NULL;
 	strcpy(refpath, mkpath("refs/%s", ref));
-	return lock_ref_sha1_basic(refpath, old_sha1);
+	return lock_ref_sha1_basic(refpath, old_sha1, NULL);
 }
 
 struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1)
 {
-	return lock_ref_sha1_basic(ref, old_sha1);
+	return lock_ref_sha1_basic(ref, old_sha1, NULL);
+}
+
+static int repack_without_ref(const char *refname)
+{
+	struct ref_list *list, *packed_ref_list;
+	int fd;
+	int found = 0;
+	struct lock_file packlock;
+
+	packed_ref_list = get_packed_refs();
+	for (list = packed_ref_list; list; list = list->next) {
+		if (!strcmp(refname, list->name)) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found)
+		return 0;
+	memset(&packlock, 0, sizeof(packlock));
+	fd = hold_lock_file_for_update(&packlock, git_path("packed-refs"), 0);
+	if (fd < 0)
+		return error("cannot delete '%s' from packed refs", refname);
+
+	for (list = packed_ref_list; list; list = list->next) {
+		char line[PATH_MAX + 100];
+		int len;
+
+		if (!strcmp(refname, list->name))
+			continue;
+		len = snprintf(line, sizeof(line), "%s %s\n",
+			       sha1_to_hex(list->sha1), list->name);
+		/* this should not happen but just being defensive */
+		if (len > sizeof(line))
+			die("too long a refname '%s'", list->name);
+		write_or_die(fd, line, len);
+	}
+	return commit_lock_file(&packlock);
+}
+
+int delete_ref(const char *refname, unsigned char *sha1)
+{
+	struct ref_lock *lock;
+	int err, i, ret = 0, flag = 0;
+
+	lock = lock_ref_sha1_basic(refname, sha1, &flag);
+	if (!lock)
+		return 1;
+	if (!(flag & REF_ISPACKED)) {
+		/* loose */
+		i = strlen(lock->lk->filename) - 5; /* .lock */
+		lock->lk->filename[i] = 0;
+		err = unlink(lock->lk->filename);
+		if (err) {
+			ret = 1;
+			error("unlink(%s) failed: %s",
+			      lock->lk->filename, strerror(errno));
+		}
+		lock->lk->filename[i] = '.';
+	}
+	/* removing the loose one could have resurrected an earlier
+	 * packed one.  Also, if it was not loose we need to repack
+	 * without it.
+	 */
+	ret |= repack_without_ref(refname);
+
+	err = unlink(lock->log_file);
+	if (err && errno != ENOENT)
+		fprintf(stderr, "warning: unlink(%s) failed: %s",
+			lock->log_file, strerror(errno));
+	invalidate_cached_refs();
+	unlock_ref(lock);
+	return ret;
 }
 
 void unlock_ref(struct ref_lock *lock)
-- 
1.4.2.1.g5a98f

  parent reply	other threads:[~2006-09-30 22:31 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-09-30 20:01 [PATCH 1/2] Move code resolving packed refs into its own function Christian Couder
2006-09-30 20:33 ` Junio C Hamano
2006-09-30 22:26   ` [PATCH 0/6] ref deletion and D/F conflict avoidance with packed-refs Junio C Hamano
2006-09-30 22:29     ` [PATCH 1/6] ref locking: allow 'foo' when 'foo/bar' used to exist but not anymore Junio C Hamano
2006-09-30 22:30     ` [PATCH 2/6] refs: minor restructuring of cached refs data Junio C Hamano
2006-09-30 22:30     ` [PATCH 3/6] lock_ref_sha1(): do not sometimes error() and sometimes die() Junio C Hamano
2006-09-30 22:30     ` [PATCH 4/6] lock_ref_sha1(): check D/F conflict with packed ref when creating Junio C Hamano
2006-09-30 22:30     ` Junio C Hamano [this message]
2006-09-30 22:30     ` [PATCH 6/6] git-branch: remove D/F check done by hand Junio C Hamano
2006-09-30 22:36     ` [PATCH 0/6] ref deletion and D/F conflict avoidance with packed-refs Jeff King
2006-10-01  4:06   ` [PATCH 1/2] Move code resolving packed refs into its own function Christian Couder
2006-10-01  9:58     ` Junio C Hamano
2006-10-03 12:10       ` Jakub Narebski
2006-10-03 17:39         ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7vac4h9ecp.fsf@assigned-by-dhcp.cox.net \
    --to=junkio@cox.net \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox