From: Ronnie Sahlberg <sahlb...@google.com>

Use a transaction for all updates during expire_reflog.

Signed-off-by: Ronnie Sahlberg <sahlb...@google.com>
Signed-off-by: Stefan Beller <sbel...@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

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to