git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 07/13] reflog.c: use a reflog transaction when writing during expire

From
Stefan Beller <sbeller@google.com>
Date
Dec 4, 2014, 08:29 UTC
Message-ID
<1417681763-32334-8-git-send-email-sbeller@google.com>
In-Reply-To
<1417681763-32334-1-git-send-email-sbeller@google.com>
From: Ronnie Sahlberg <sahlberg@google.com>
Use a transaction for all updates during expire_reflog.
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
Notes:
    Jonathan writes:
    > This doesn't match the signature of each_reflog_ent_fn.  Would putting
    > err in the cb_data struct work?
    
    That's what I do in this update.
 builtin/reflog.c | 84 ++++++++++++++++++++++++--------------------------------
 1 file changed, 36 insertions(+), 48 deletions(-)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 2d85d26..e13427c 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -33,7 +33,8 @@ struct cmd_reflog_expire_cb {
 };
 
 struct expire_reflog_cb {
-	FILE *newlog;
+	struct transaction *t;
+	const char *refname;
 	enum {
 		UE_NORMAL,
 		UE_ALWAYS,
@@ -43,6 +44,7 @@ struct expire_reflog_cb {
 	unsigned long mark_limit;
 	struct cmd_reflog_expire_cb *cmd;
 	unsigned char last_kept_sha1[20];
+	struct strbuf *err;
 };
 
 struct collected_reflog {
@@ -316,20 +318,18 @@ static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
 	if (cb->cmd->recno && --(cb->cmd->recno) == 0)
 		goto prune;
 
-	if (cb->newlog) {
-		char sign = (tz < 0) ? '-' : '+';
-		int zone = (tz < 0) ? (-tz) : tz;
-		fprintf(cb->newlog, "%s %s %s %lu %c%04d\t%s",
-			sha1_to_hex(osha1), sha1_to_hex(nsha1),
-			email, timestamp, sign, zone,
-			message);
+	if (cb->t) {
+		if (transaction_update_reflog(cb->t, cb->refname, nsha1, osha1,
+					      email, timestamp, tz, message,
+					      cb->err))
+			return -1;
 		hashcpy(cb->last_kept_sha1, nsha1);
 	}
 	if (cb->cmd->verbose)
 		printf("keep %s", message);
 	return 0;
  prune:
-	if (!cb->newlog)
+	if (!cb->t)
 		printf("would prune %s", message);
 	else if (cb->cmd->verbose)
 		printf("prune %s", message);
@@ -353,29 +353,26 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
 {
 	struct cmd_reflog_expire_cb *cmd = cb_data;
 	struct expire_reflog_cb cb;
-	struct ref_lock *lock;
-	char *log_file, *newlog_path = NULL;
 	struct commit *tip_commit;
 	struct commit_list *tips;
+	struct strbuf err = STRBUF_INIT;
 	int status = 0;
 
 	memset(&cb, 0, sizeof(cb));
+	cb.refname = ref;
+	cb.err = &err;
 
-	/*
-	 * we take the lock for the ref itself to prevent it from
-	 * getting updated.
-	 */
-	lock = lock_any_ref_for_update(ref, sha1, 0, NULL);
-	if (!lock)
-		return error("cannot lock ref '%s'", ref);
-	log_file = git_pathdup("logs/%s", ref);
 	if (!reflog_exists(ref))
 		goto finish;
-	if (!cmd->dry_run) {
-		newlog_path = git_pathdup("logs/%s.lock", ref);
-		cb.newlog = fopen(newlog_path, "w");
+	cb.t = transaction_begin(&err);
+	if (!cb.t) {
+		status |= error("%s", err.buf);
+		goto cleanup;
+	}
+	if (transaction_truncate_reflog(cb.t, cb.refname, &err)) {
+		status |= error("%s", err.buf);
+		goto cleanup;
 	}
-
 	cb.cmd = cmd;
 
 	if (!cmd->expire_unreachable || !strcmp(ref, "HEAD")) {
@@ -407,7 +404,10 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
 		mark_reachable(&cb);
 	}
 
-	for_each_reflog_ent(ref, expire_reflog_ent, &cb);
+	if (for_each_reflog_ent(ref, expire_reflog_ent, &cb)) {
+		status |= error("%s", err.buf);
+		goto cleanup;
+	}
 
 	if (cb.unreachable_expire_kind != UE_ALWAYS) {
 		if (cb.unreachable_expire_kind == UE_HEAD) {
@@ -420,32 +420,20 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
 		}
 	}
  finish:
-	if (cb.newlog) {
-		if (fclose(cb.newlog)) {
-			status |= error("%s: %s", strerror(errno),
-					newlog_path);
-			unlink(newlog_path);
-		} else if (cmd->updateref &&
-			(write_in_full(lock->lock_fd,
-				sha1_to_hex(cb.last_kept_sha1), 40) != 40 ||
-			 write_str_in_full(lock->lock_fd, "\n") != 1 ||
-			 close_ref(lock) < 0)) {
-			status |= error("Couldn't write %s",
-					lock->lk->filename.buf);
-			unlink(newlog_path);
-		} else if (rename(newlog_path, log_file)) {
-			status |= error("cannot rename %s to %s",
-					newlog_path, log_file);
-			unlink(newlog_path);
-		} else if (cmd->updateref && commit_ref(lock)) {
-			status |= error("Couldn't set %s", lock->ref_name);
-		} else {
-			adjust_shared_perm(log_file);
+	if (!cmd->dry_run) {
+		if (cmd->updateref &&
+		    transaction_update_ref(cb.t, cb.refname,
+					   cb.last_kept_sha1, sha1,
+					   0, 1, NULL, &err)) {
+			status |= error("%s", err.buf);
+			goto cleanup;
 		}
+		if (transaction_commit(cb.t, &err))
+			status |= error("%s", err.buf);
 	}
-	free(newlog_path);
-	free(log_file);
-	unlock_ref(lock);
+ cleanup:
+	transaction_free(cb.t);
+	strbuf_release(&err);
 	return status;
 }
 
-- 
2.2.0
Previous: Stefan BellerNext: Stefan Beller
Message 8 of 25 in “[PATCHv3 00/13] the refs-transactions-reflog series”
  1. Stefan BellerDec 4, 2014
  2. 01/13 refs.c: make ref_transaction_create a wrapper for ref_transaction_updateStefan Beller, Dec 4, 2014
  3. 02/13 refs.c: make ref_transaction_delete a wrapper for ref_transaction_updateStefan Beller, Dec 4, 2014
  4. 03/13 refs.c: add a function to append a reflog entry to a fdStefan Beller, Dec 4, 2014
  5. 04/13 refs.c: rename the transaction functionsStefan Beller, Dec 4, 2014
  6. 05/13 refs.c: rename transaction.updates to transaction.ref_updatesStefan Beller, Dec 4, 2014
  7. 06/13 refs.c: add a transaction function to truncate or append a reflog entryStefan Beller, Dec 4, 2014
  8. 07/13 reflog.c: use a reflog transaction when writing during expireStefan Beller, Dec 4, 2014
  9. 08/13 refs.c: rename log_ref_setup to create_reflogStefan Beller, Dec 4, 2014
  10. 09/13 refs.c: remove unlock_ref/close_ref/commit_ref from the refs apiStefan Beller, Dec 4, 2014
  11. 10/13 refs.c: remove lock_any_ref_for_updateStefan Beller, Dec 4, 2014
  12. 11/13 refs.c: don't expose the internal struct ref_lock in the header fileStefan Beller, Dec 4, 2014
  13. 12/13 refs.c: use a bit for ref_update have_oldStefan Beller, Dec 4, 2014
  14. Torsten BögershausenDec 4, 2014
  15. Andreas SchwabDec 4, 2014
  16. 13/13 refs.c: allow deleting refs with a broken sha1Stefan Beller, Dec 4, 2014
  17. Michael HaggertyDec 4, 2014
  18. Jonathan NiederDec 4, 2014
  19. Jonathan NiederDec 4, 2014
  20. Stefan BellerDec 4, 2014
  21. Michael HaggertyDec 4, 2014
  22. Junio C HamanoDec 4, 2014
  23. Junio C HamanoDec 4, 2014
  24. Stefan BellerDec 4, 2014
  25. Jonathan NiederDec 4, 2014

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.