* [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire
2014-11-27 5:34 ` [PATCH 0/4] Using transactions for the reflog Stefan Beller
@ 2014-11-27 5:34 ` Stefan Beller
0 siblings, 0 replies; 14+ messages in thread
From: Stefan Beller @ 2014-11-27 5:34 UTC (permalink / raw)
To: ronniesahlberg, gitster, mhagger, jrnieder, git
Cc: Ronnie Sahlberg, Stefan Beller
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>
---
builtin/reflog.c | 85 ++++++++++++++++++++++++--------------------------------
1 file changed, 37 insertions(+), 48 deletions(-)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 2d85d26..6bb7454 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -32,8 +32,11 @@ struct cmd_reflog_expire_cb {
int recno;
};
+static struct strbuf err = STRBUF_INIT;
+
struct expire_reflog_cb {
- FILE *newlog;
+ struct transaction *t;
+ const char *refname;
enum {
UE_NORMAL,
UE_ALWAYS,
@@ -316,20 +319,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, 0,
+ &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 +354,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;
int status = 0;
memset(&cb, 0, sizeof(cb));
+ cb.refname = ref;
- /*
- * 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_update_reflog(cb.t, cb.refname, null_sha1, null_sha1,
+ NULL, 0, 0, NULL, REFLOG_TRUNCATE,
+ &err)) {
+ status |= error("%s", err.buf);
+ goto cleanup;
}
-
cb.cmd = cmd;
if (!cmd->expire_unreachable || !strcmp(ref, "HEAD")) {
@@ -407,7 +405,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 +421,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.rc3
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire
2014-12-02 2:02 [PATCH 1/4] refs.c: rename the transaction functions Stefan Beller
@ 2014-12-02 2:02 ` Stefan Beller
0 siblings, 0 replies; 14+ messages in thread
From: Stefan Beller @ 2014-12-02 2:02 UTC (permalink / raw)
To: jrnieder, git
From: Ronnie Sahlberg <sahlberg@google.com>
Use a transaction for all updates during expire_reflog.
Change-Id: Ieb81b2660cefeeecf0bcb3cdbc1ef3cbb86e7eb8
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
builtin/reflog.c | 85 ++++++++++++++++++++++++--------------------------------
1 file changed, 37 insertions(+), 48 deletions(-)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 2d85d26..6bb7454 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -32,8 +32,11 @@ struct cmd_reflog_expire_cb {
int recno;
};
+static struct strbuf err = STRBUF_INIT;
+
struct expire_reflog_cb {
- FILE *newlog;
+ struct transaction *t;
+ const char *refname;
enum {
UE_NORMAL,
UE_ALWAYS,
@@ -316,20 +319,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, 0,
+ &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 +354,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;
int status = 0;
memset(&cb, 0, sizeof(cb));
+ cb.refname = ref;
- /*
- * 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_update_reflog(cb.t, cb.refname, null_sha1, null_sha1,
+ NULL, 0, 0, NULL, REFLOG_TRUNCATE,
+ &err)) {
+ status |= error("%s", err.buf);
+ goto cleanup;
}
-
cb.cmd = cmd;
if (!cmd->expire_unreachable || !strcmp(ref, "HEAD")) {
@@ -407,7 +405,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 +421,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
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCHv2 0/4] refs.c: use transactions for the reflog
@ 2014-12-02 7:46 Stefan Beller
2014-12-02 7:46 ` [PATCH 1/4] refs.c: rename the transaction functions Stefan Beller
` (4 more replies)
0 siblings, 5 replies; 14+ messages in thread
From: Stefan Beller @ 2014-12-02 7:46 UTC (permalink / raw)
To: gitster, git, ronniesahlberg, mhagger, jrnieder; +Cc: Stefan Beller
This is the core part of the refs-transactions-reflog series[1],
which was in discussion for a bit already.
The idea is to have the reflog being part of the transactions, which
the refs are already using, so the we're moving towards a database
like API in the long run. This makes git easier to maintain as well
as opening the possibility to replace the backend with a real database.
The first patch is essentially just some sed magic with reformatting
the code, so the naming convention fits better, because the transactions
will handle both the refs as well as the reflog after this series.
The second patch is also just a rename patch.
The meat and most of the lines of code are found in the 3rd patch.
It was completely rewritten from scratch using ideas provided by
Jonathan, thanks! We'll treat the refs and reflogs a bit differently
within the transaction updates data structure, as the hard part for
the refs is during the commit phase, while the hard part for the reflogs
is during the preparation phase now.
We're using a temporary file for creating the new reflog and rename it
into place afterwards utilizing the lock file API.
The last patch makes actually use of the reflog transaction API.
Any comments would be appreciated,
Thanks,
Stefan
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/4] refs.c: rename the transaction functions
2014-12-02 7:46 [PATCHv2 0/4] refs.c: use transactions for the reflog Stefan Beller
@ 2014-12-02 7:46 ` Stefan Beller
2014-12-03 2:24 ` Jonathan Nieder
2014-12-02 7:46 ` [PATCH 2/4] refs.c: rename transaction.updates to transaction.ref_updates Stefan Beller
` (3 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Stefan Beller @ 2014-12-02 7:46 UTC (permalink / raw)
To: gitster, git, ronniesahlberg, mhagger, jrnieder
Cc: Ronnie Sahlberg, Stefan Beller
From: Ronnie Sahlberg <sahlberg@google.com>
Rename the transaction functions. Remove the leading ref_ from the
names and append _ref to the names for functions that create/delete/
update sha1 refs.
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
This commit can be reproduced via
find . -name "*.[ch]" -print | xargs sed -i ' \
s/REF_TRANSACTION_OPEN/TRANSACTION_OPEN/; \
s/REF_TRANSACTION_CLOSED/TRANSACTION_CLOSED/; \
s/ref_transaction_begin/transaction_begin/; \
s/ref_transaction_commit/transaction_commit/; \
s/ref_transaction_create/transaction_create_ref/; \
s/ref_transaction_delete/transaction_delete_ref/; \
s/ref_transaction_free/transaction_free/; \
s/ref_transaction_update/transaction_update_ref/; \
s/ref_transaction/transaction/'
modulo white space changes for alignment.
No changes since sending it 5 days ago.
branch.c | 13 +++++----
builtin/commit.c | 10 +++----
builtin/fetch.c | 12 ++++----
builtin/receive-pack.c | 13 ++++-----
builtin/replace.c | 10 +++----
builtin/tag.c | 10 +++----
builtin/update-ref.c | 26 ++++++++---------
fast-import.c | 22 +++++++-------
refs.c | 78 +++++++++++++++++++++++++-------------------------
refs.h | 36 +++++++++++------------
sequencer.c | 12 ++++----
walker.c | 10 +++----
12 files changed, 126 insertions(+), 126 deletions(-)
diff --git a/branch.c b/branch.c
index 4bab55a..c8462de 100644
--- a/branch.c
+++ b/branch.c
@@ -279,16 +279,17 @@ void create_branch(const char *head,
log_all_ref_updates = 1;
if (!dont_change_ref) {
- struct ref_transaction *transaction;
+ struct transaction *transaction;
struct strbuf err = STRBUF_INIT;
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref.buf, sha1,
- null_sha1, 0, !forcing, msg, &err) ||
- ref_transaction_commit(transaction, &err))
+ transaction_update_ref(transaction, ref.buf, sha1,
+ null_sha1, 0, !forcing, msg,
+ &err) ||
+ transaction_commit(transaction, &err))
die("%s", err.buf);
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&err);
}
diff --git a/builtin/commit.c b/builtin/commit.c
index e108c53..f50b7df 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1673,7 +1673,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
struct stat statbuf;
struct commit *current_head = NULL;
struct commit_extra_header *extra = NULL;
- struct ref_transaction *transaction;
+ struct transaction *transaction;
struct strbuf err = STRBUF_INIT;
if (argc == 2 && !strcmp(argv[1], "-h"))
@@ -1804,17 +1804,17 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
strbuf_insert(&sb, 0, reflog_msg, strlen(reflog_msg));
strbuf_insert(&sb, strlen(reflog_msg), ": ", 2);
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, "HEAD", sha1,
+ transaction_update_ref(transaction, "HEAD", sha1,
current_head
? current_head->object.sha1 : NULL,
0, !!current_head, sb.buf, &err) ||
- ref_transaction_commit(transaction, &err)) {
+ transaction_commit(transaction, &err)) {
rollback_index_files();
die("%s", err.buf);
}
- ref_transaction_free(transaction);
+ transaction_free(transaction);
unlink(git_path("CHERRY_PICK_HEAD"));
unlink(git_path("REVERT_HEAD"));
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7b84d35..0be0b09 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -404,7 +404,7 @@ static int s_update_ref(const char *action,
{
char msg[1024];
char *rla = getenv("GIT_REFLOG_ACTION");
- struct ref_transaction *transaction;
+ struct transaction *transaction;
struct strbuf err = STRBUF_INIT;
int ret, df_conflict = 0;
@@ -414,23 +414,23 @@ static int s_update_ref(const char *action,
rla = default_rla.buf;
snprintf(msg, sizeof(msg), "%s: %s", rla, action);
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref->name, ref->new_sha1,
+ transaction_update_ref(transaction, ref->name, ref->new_sha1,
ref->old_sha1, 0, check_old, msg, &err))
goto fail;
- ret = ref_transaction_commit(transaction, &err);
+ ret = transaction_commit(transaction, &err);
if (ret) {
df_conflict = (ret == TRANSACTION_NAME_CONFLICT);
goto fail;
}
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&err);
return 0;
fail:
- ref_transaction_free(transaction);
+ transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&err);
return df_conflict ? STORE_REF_ERROR_DF_CONFLICT
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 32fc540..397abc9 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -838,26 +838,25 @@ static const char *update(struct command *cmd, struct shallow_info *si)
}
else {
struct strbuf err = STRBUF_INIT;
- struct ref_transaction *transaction;
+ struct transaction *transaction;
if (shallow_update && si->shallow_ref[cmd->index] &&
update_shallow_ref(cmd, si))
return "shallow error";
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, namespaced_name,
+ transaction_update_ref(transaction, namespaced_name,
new_sha1, old_sha1, 0, 1, "push",
&err) ||
- ref_transaction_commit(transaction, &err)) {
- ref_transaction_free(transaction);
-
+ transaction_commit(transaction, &err)) {
+ transaction_free(transaction);
rp_error("%s", err.buf);
strbuf_release(&err);
return "failed to update ref";
}
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&err);
return NULL; /* good */
}
diff --git a/builtin/replace.c b/builtin/replace.c
index 85d39b5..5a7ab1f 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -155,7 +155,7 @@ static int replace_object_sha1(const char *object_ref,
unsigned char prev[20];
enum object_type obj_type, repl_type;
char ref[PATH_MAX];
- struct ref_transaction *transaction;
+ struct transaction *transaction;
struct strbuf err = STRBUF_INIT;
obj_type = sha1_object_info(object, NULL);
@@ -169,14 +169,14 @@ static int replace_object_sha1(const char *object_ref,
check_ref_valid(object, prev, ref, sizeof(ref), force);
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref, repl, prev,
+ transaction_update_ref(transaction, ref, repl, prev,
0, 1, NULL, &err) ||
- ref_transaction_commit(transaction, &err))
+ transaction_commit(transaction, &err))
die("%s", err.buf);
- ref_transaction_free(transaction);
+ transaction_free(transaction);
return 0;
}
diff --git a/builtin/tag.c b/builtin/tag.c
index e633f4e..5f3554b 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -583,7 +583,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
const char *msgfile = NULL, *keyid = NULL;
struct msg_arg msg = { 0, STRBUF_INIT };
struct commit_list *with_commit = NULL;
- struct ref_transaction *transaction;
+ struct transaction *transaction;
struct strbuf err = STRBUF_INIT;
struct option options[] = {
OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
@@ -730,13 +730,13 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
if (annotate)
create_tag(object, tag, &buf, &opt, prev, object);
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref.buf, object, prev,
+ transaction_update_ref(transaction, ref.buf, object, prev,
0, 1, NULL, &err) ||
- ref_transaction_commit(transaction, &err))
+ transaction_commit(transaction, &err))
die("%s", err.buf);
- ref_transaction_free(transaction);
+ transaction_free(transaction);
if (force && !is_null_sha1(prev) && hashcmp(prev, object))
printf(_("Updated tag '%s' (was %s)\n"), tag, find_unique_abbrev(prev, DEFAULT_ABBREV));
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 6c9be05..af08dd9 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -175,7 +175,7 @@ static int parse_next_sha1(struct strbuf *input, const char **next,
* depending on how line_termination is set.
*/
-static const char *parse_cmd_update(struct ref_transaction *transaction,
+static const char *parse_cmd_update(struct transaction *transaction,
struct strbuf *input, const char *next)
{
struct strbuf err = STRBUF_INIT;
@@ -198,7 +198,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
if (*next != line_termination)
die("update %s: extra input: %s", refname, next);
- if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
+ if (transaction_update_ref(transaction, refname, new_sha1, old_sha1,
update_flags, have_old, msg, &err))
die("%s", err.buf);
@@ -209,7 +209,7 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
return next;
}
-static const char *parse_cmd_create(struct ref_transaction *transaction,
+static const char *parse_cmd_create(struct transaction *transaction,
struct strbuf *input, const char *next)
{
struct strbuf err = STRBUF_INIT;
@@ -229,7 +229,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
- if (ref_transaction_create(transaction, refname, new_sha1,
+ if (transaction_create_ref(transaction, refname, new_sha1,
update_flags, msg, &err))
die("%s", err.buf);
@@ -240,7 +240,7 @@ static const char *parse_cmd_create(struct ref_transaction *transaction,
return next;
}
-static const char *parse_cmd_delete(struct ref_transaction *transaction,
+static const char *parse_cmd_delete(struct transaction *transaction,
struct strbuf *input, const char *next)
{
struct strbuf err = STRBUF_INIT;
@@ -264,7 +264,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
if (*next != line_termination)
die("delete %s: extra input: %s", refname, next);
- if (ref_transaction_delete(transaction, refname, old_sha1,
+ if (transaction_delete_ref(transaction, refname, old_sha1,
update_flags, have_old, msg, &err))
die("%s", err.buf);
@@ -275,7 +275,7 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
return next;
}
-static const char *parse_cmd_verify(struct ref_transaction *transaction,
+static const char *parse_cmd_verify(struct transaction *transaction,
struct strbuf *input, const char *next)
{
struct strbuf err = STRBUF_INIT;
@@ -300,7 +300,7 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
if (*next != line_termination)
die("verify %s: extra input: %s", refname, next);
- if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
+ if (transaction_update_ref(transaction, refname, new_sha1, old_sha1,
update_flags, have_old, msg, &err))
die("%s", err.buf);
@@ -320,7 +320,7 @@ static const char *parse_cmd_option(struct strbuf *input, const char *next)
return next + 8;
}
-static void update_refs_stdin(struct ref_transaction *transaction)
+static void update_refs_stdin(struct transaction *transaction)
{
struct strbuf input = STRBUF_INIT;
const char *next;
@@ -376,9 +376,9 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
if (read_stdin) {
struct strbuf err = STRBUF_INIT;
- struct ref_transaction *transaction;
+ struct transaction *transaction;
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction)
die("%s", err.buf);
if (delete || no_deref || argc > 0)
@@ -386,9 +386,9 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
if (end_null)
line_termination = '\0';
update_refs_stdin(transaction);
- if (ref_transaction_commit(transaction, &err))
+ if (transaction_commit(transaction, &err))
die("%s", err.buf);
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&err);
return 0;
}
diff --git a/fast-import.c b/fast-import.c
index d0bd285..152d944 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -1687,7 +1687,7 @@ found_entry:
static int update_branch(struct branch *b)
{
static const char *msg = "fast-import";
- struct ref_transaction *transaction;
+ struct transaction *transaction;
unsigned char old_sha1[20];
struct strbuf err = STRBUF_INIT;
@@ -1713,17 +1713,17 @@ static int update_branch(struct branch *b)
return -1;
}
}
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
+ transaction_update_ref(transaction, b->name, b->sha1, old_sha1,
0, 1, msg, &err) ||
- ref_transaction_commit(transaction, &err)) {
- ref_transaction_free(transaction);
+ transaction_commit(transaction, &err)) {
+ transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&err);
return -1;
}
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&err);
return 0;
}
@@ -1745,9 +1745,9 @@ static void dump_tags(void)
struct tag *t;
struct strbuf ref_name = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
- struct ref_transaction *transaction;
+ struct transaction *transaction;
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction) {
failure |= error("%s", err.buf);
goto cleanup;
@@ -1756,17 +1756,17 @@ static void dump_tags(void)
strbuf_reset(&ref_name);
strbuf_addf(&ref_name, "refs/tags/%s", t->name);
- if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
+ if (transaction_update_ref(transaction, ref_name.buf, t->sha1,
NULL, 0, 0, msg, &err)) {
failure |= error("%s", err.buf);
goto cleanup;
}
}
- if (ref_transaction_commit(transaction, &err))
+ if (transaction_commit(transaction, &err))
failure |= error("%s", err.buf);
cleanup:
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&ref_name);
strbuf_release(&err);
}
diff --git a/refs.c b/refs.c
index 150c980..f0f0d23 100644
--- a/refs.c
+++ b/refs.c
@@ -26,7 +26,7 @@ static unsigned char refname_disposition[256] = {
};
/*
- * Used as a flag to ref_transaction_delete when a loose ref is being
+ * Used as a flag to transaction_delete_ref when a loose ref is being
* pruned.
*/
#define REF_ISPRUNING 0x0100
@@ -2533,23 +2533,23 @@ static void try_remove_empty_parents(char *name)
/* make sure nobody touched the ref, and unlink */
static void prune_ref(struct ref_to_prune *r)
{
- struct ref_transaction *transaction;
+ struct transaction *transaction;
struct strbuf err = STRBUF_INIT;
if (check_refname_format(r->name, 0))
return;
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_delete(transaction, r->name, r->sha1,
+ transaction_delete_ref(transaction, r->name, r->sha1,
REF_ISPRUNING, 1, NULL, &err) ||
- ref_transaction_commit(transaction, &err)) {
- ref_transaction_free(transaction);
+ transaction_commit(transaction, &err)) {
+ transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&err);
return;
}
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&err);
try_remove_empty_parents(r->name);
}
@@ -2711,20 +2711,20 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)
int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
{
- struct ref_transaction *transaction;
+ struct transaction *transaction;
struct strbuf err = STRBUF_INIT;
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_delete(transaction, refname, sha1, delopt,
+ transaction_delete_ref(transaction, refname, sha1, delopt,
sha1 && !is_null_sha1(sha1), NULL, &err) ||
- ref_transaction_commit(transaction, &err)) {
+ transaction_commit(transaction, &err)) {
error("%s", err.buf);
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&err);
return 1;
}
- ref_transaction_free(transaction);
+ transaction_free(transaction);
strbuf_release(&err);
return 0;
}
@@ -3543,9 +3543,9 @@ struct ref_update {
* an active transaction or if there is a failure while building
* the transaction thus rendering it failed/inactive.
*/
-enum ref_transaction_state {
- REF_TRANSACTION_OPEN = 0,
- REF_TRANSACTION_CLOSED = 1
+enum transaction_state {
+ TRANSACTION_OPEN = 0,
+ TRANSACTION_CLOSED = 1
};
/*
@@ -3553,21 +3553,21 @@ enum ref_transaction_state {
* consist of checks and updates to multiple references, carried out
* as atomically as possible. This structure is opaque to callers.
*/
-struct ref_transaction {
+struct transaction {
struct ref_update **updates;
size_t alloc;
size_t nr;
- enum ref_transaction_state state;
+ enum transaction_state state;
};
-struct ref_transaction *ref_transaction_begin(struct strbuf *err)
+struct transaction *transaction_begin(struct strbuf *err)
{
assert(err);
- return xcalloc(1, sizeof(struct ref_transaction));
+ return xcalloc(1, sizeof(struct transaction));
}
-void ref_transaction_free(struct ref_transaction *transaction)
+void transaction_free(struct transaction *transaction)
{
int i;
@@ -3582,7 +3582,7 @@ void ref_transaction_free(struct ref_transaction *transaction)
free(transaction);
}
-static struct ref_update *add_update(struct ref_transaction *transaction,
+static struct ref_update *add_update(struct transaction *transaction,
const char *refname)
{
size_t len = strlen(refname);
@@ -3594,7 +3594,7 @@ static struct ref_update *add_update(struct ref_transaction *transaction,
return update;
}
-int ref_transaction_update(struct ref_transaction *transaction,
+int transaction_update_ref(struct transaction *transaction,
const char *refname,
const unsigned char *new_sha1,
const unsigned char *old_sha1,
@@ -3605,7 +3605,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
assert(err);
- if (transaction->state != REF_TRANSACTION_OPEN)
+ if (transaction->state != TRANSACTION_OPEN)
die("BUG: update called for transaction that is not open");
if (have_old && !old_sha1)
@@ -3629,23 +3629,23 @@ int ref_transaction_update(struct ref_transaction *transaction,
return 0;
}
-int ref_transaction_create(struct ref_transaction *transaction,
+int transaction_create_ref(struct transaction *transaction,
const char *refname,
const unsigned char *new_sha1,
int flags, const char *msg,
struct strbuf *err)
{
- return ref_transaction_update(transaction, refname, new_sha1,
+ return transaction_update_ref(transaction, refname, new_sha1,
null_sha1, flags, 1, msg, err);
}
-int ref_transaction_delete(struct ref_transaction *transaction,
+int transaction_delete_ref(struct transaction *transaction,
const char *refname,
const unsigned char *old_sha1,
int flags, int have_old, const char *msg,
struct strbuf *err)
{
- return ref_transaction_update(transaction, refname, null_sha1,
+ return transaction_update_ref(transaction, refname, null_sha1,
old_sha1, flags, have_old, msg, err);
}
@@ -3653,17 +3653,17 @@ int update_ref(const char *action, const char *refname,
const unsigned char *sha1, const unsigned char *oldval,
int flags, enum action_on_err onerr)
{
- struct ref_transaction *t;
+ struct transaction *t;
struct strbuf err = STRBUF_INIT;
- t = ref_transaction_begin(&err);
+ t = transaction_begin(&err);
if (!t ||
- ref_transaction_update(t, refname, sha1, oldval, flags,
+ transaction_update_ref(t, refname, sha1, oldval, flags,
!!oldval, action, &err) ||
- ref_transaction_commit(t, &err)) {
+ transaction_commit(t, &err)) {
const char *str = "update_ref failed for ref '%s': %s";
- ref_transaction_free(t);
+ transaction_free(t);
switch (onerr) {
case UPDATE_REFS_MSG_ON_ERR:
error(str, refname, err.buf);
@@ -3678,7 +3678,7 @@ int update_ref(const char *action, const char *refname,
return 1;
}
strbuf_release(&err);
- ref_transaction_free(t);
+ transaction_free(t);
return 0;
}
@@ -3706,8 +3706,8 @@ static int ref_update_reject_duplicates(struct ref_update **updates, int n,
return 0;
}
-int ref_transaction_commit(struct ref_transaction *transaction,
- struct strbuf *err)
+int transaction_commit(struct transaction *transaction,
+ struct strbuf *err)
{
int ret = 0, delnum = 0, i;
const char **delnames;
@@ -3716,11 +3716,11 @@ int ref_transaction_commit(struct ref_transaction *transaction,
assert(err);
- if (transaction->state != REF_TRANSACTION_OPEN)
+ if (transaction->state != TRANSACTION_OPEN)
die("BUG: commit called for transaction that is not open");
if (!n) {
- transaction->state = REF_TRANSACTION_CLOSED;
+ transaction->state = TRANSACTION_CLOSED;
return 0;
}
@@ -3799,7 +3799,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
clear_loose_ref_cache(&ref_cache);
cleanup:
- transaction->state = REF_TRANSACTION_CLOSED;
+ transaction->state = TRANSACTION_CLOSED;
for (i = 0; i < n; i++)
if (updates[i]->lock)
diff --git a/refs.h b/refs.h
index 7d675b7..556adfd 100644
--- a/refs.h
+++ b/refs.h
@@ -11,22 +11,22 @@ struct ref_lock {
};
/*
- * A ref_transaction represents a collection of ref updates
+ * A transaction represents a collection of ref updates
* that should succeed or fail together.
*
* Calling sequence
* ----------------
- * - Allocate and initialize a `struct ref_transaction` by calling
- * `ref_transaction_begin()`.
+ * - Allocate and initialize a `struct transaction` by calling
+ * `transaction_begin()`.
*
* - List intended ref updates by calling functions like
- * `ref_transaction_update()` and `ref_transaction_create()`.
+ * `transaction_update_ref()` and `transaction_create_ref()`.
*
- * - Call `ref_transaction_commit()` to execute the transaction.
+ * - Call `transaction_commit()` to execute the transaction.
* If this succeeds, the ref updates will have taken place and
* the transaction cannot be rolled back.
*
- * - At any time call `ref_transaction_free()` to discard the
+ * - At any time call `transaction_free()` to discard the
* transaction and free associated resources. In particular,
* this rolls back the transaction if it has not been
* successfully committed.
@@ -42,7 +42,7 @@ struct ref_lock {
* The message is appended to err without first clearing err.
* err will not be '\n' terminated.
*/
-struct ref_transaction;
+struct transaction;
/*
* Bit values set in the flags argument passed to each_ref_fn():
@@ -181,8 +181,8 @@ extern int is_branch(const char *refname);
extern int peel_ref(const char *refname, unsigned char *sha1);
/*
- * Flags controlling lock_any_ref_for_update(), ref_transaction_update(),
- * ref_transaction_create(), etc.
+ * Flags controlling lock_any_ref_for_update(), transaction_update_ref(),
+ * transaction_create_ref(), etc.
* REF_NODEREF: act on the ref directly, instead of dereferencing
* symbolic references.
* REF_DELETING: tolerate broken refs
@@ -269,13 +269,13 @@ enum action_on_err {
/*
* Begin a reference transaction. The reference transaction must
- * be freed by calling ref_transaction_free().
+ * be freed by calling transaction_free().
*/
-struct ref_transaction *ref_transaction_begin(struct strbuf *err);
+struct transaction *transaction_begin(struct strbuf *err);
/*
* The following functions add a reference check or update to a
- * ref_transaction. In all of them, refname is the name of the
+ * transaction. In all of them, refname is the name of the
* reference to be affected. The functions make internal copies of
* refname and msg, so the caller retains ownership of these parameters.
* flags can be REF_NODEREF; it is passed to update_ref_lock().
@@ -291,7 +291,7 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err);
* means that the transaction as a whole has failed and will need to be
* rolled back.
*/
-int ref_transaction_update(struct ref_transaction *transaction,
+int transaction_update_ref(struct transaction *transaction,
const char *refname,
const unsigned char *new_sha1,
const unsigned char *old_sha1,
@@ -307,7 +307,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
* means that the transaction as a whole has failed and will need to be
* rolled back.
*/
-int ref_transaction_create(struct ref_transaction *transaction,
+int transaction_create_ref(struct transaction *transaction,
const char *refname,
const unsigned char *new_sha1,
int flags, const char *msg,
@@ -321,7 +321,7 @@ int ref_transaction_create(struct ref_transaction *transaction,
* means that the transaction as a whole has failed and will need to be
* rolled back.
*/
-int ref_transaction_delete(struct ref_transaction *transaction,
+int transaction_delete_ref(struct transaction *transaction,
const char *refname,
const unsigned char *old_sha1,
int flags, int have_old, const char *msg,
@@ -337,13 +337,13 @@ int ref_transaction_delete(struct ref_transaction *transaction,
#define TRANSACTION_NAME_CONFLICT -1
/* All other errors. */
#define TRANSACTION_GENERIC_ERROR -2
-int ref_transaction_commit(struct ref_transaction *transaction,
- struct strbuf *err);
+int transaction_commit(struct transaction *transaction,
+ struct strbuf *err);
/*
* Free an existing transaction and all associated data.
*/
-void ref_transaction_free(struct ref_transaction *transaction);
+void transaction_free(struct transaction *transaction);
/** Lock a ref and then write its file */
int update_ref(const char *action, const char *refname,
diff --git a/sequencer.c b/sequencer.c
index a03d4fa..f888005 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -238,7 +238,7 @@ static int error_dirty_index(struct replay_opts *opts)
static int fast_forward_to(const unsigned char *to, const unsigned char *from,
int unborn, struct replay_opts *opts)
{
- struct ref_transaction *transaction;
+ struct transaction *transaction;
struct strbuf sb = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
@@ -248,13 +248,13 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, "HEAD",
+ transaction_update_ref(transaction, "HEAD",
to, unborn ? null_sha1 : from,
0, 1, sb.buf, &err) ||
- ref_transaction_commit(transaction, &err)) {
- ref_transaction_free(transaction);
+ transaction_commit(transaction, &err)) {
+ transaction_free(transaction);
error("%s", err.buf);
strbuf_release(&sb);
strbuf_release(&err);
@@ -263,7 +263,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
strbuf_release(&sb);
strbuf_release(&err);
- ref_transaction_free(transaction);
+ transaction_free(transaction);
return 0;
}
diff --git a/walker.c b/walker.c
index f149371..f1d5e9b 100644
--- a/walker.c
+++ b/walker.c
@@ -253,7 +253,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
{
struct strbuf refname = STRBUF_INIT;
struct strbuf err = STRBUF_INIT;
- struct ref_transaction *transaction = NULL;
+ struct transaction *transaction = NULL;
unsigned char *sha1 = xmalloc(targets * 20);
char *msg = NULL;
int i, ret = -1;
@@ -261,7 +261,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
save_commit_buffer = 0;
if (write_ref) {
- transaction = ref_transaction_begin(&err);
+ transaction = transaction_begin(&err);
if (!transaction) {
error("%s", err.buf);
goto done;
@@ -298,7 +298,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
continue;
strbuf_reset(&refname);
strbuf_addf(&refname, "refs/%s", write_ref[i]);
- if (ref_transaction_update(transaction, refname.buf,
+ if (transaction_update_ref(transaction, refname.buf,
&sha1[20 * i], NULL, 0, 0,
msg ? msg : "fetch (unknown)",
&err)) {
@@ -306,7 +306,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
goto done;
}
}
- if (ref_transaction_commit(transaction, &err)) {
+ if (transaction_commit(transaction, &err)) {
error("%s", err.buf);
goto done;
}
@@ -314,7 +314,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
ret = 0;
done:
- ref_transaction_free(transaction);
+ transaction_free(transaction);
free(msg);
free(sha1);
strbuf_release(&err);
--
2.2.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/4] refs.c: rename transaction.updates to transaction.ref_updates
2014-12-02 7:46 [PATCHv2 0/4] refs.c: use transactions for the reflog Stefan Beller
2014-12-02 7:46 ` [PATCH 1/4] refs.c: rename the transaction functions Stefan Beller
@ 2014-12-02 7:46 ` Stefan Beller
2014-12-03 2:43 ` Jonathan Nieder
2014-12-02 7:46 ` [PATCH 3/4] refs.c: add a transaction function to append a reflog entry Stefan Beller
` (2 subsequent siblings)
4 siblings, 1 reply; 14+ messages in thread
From: Stefan Beller @ 2014-12-02 7:46 UTC (permalink / raw)
To: gitster, git, ronniesahlberg, mhagger, jrnieder; +Cc: Stefan Beller
The updates are only holding refs not reflogs, so express it to the reader.
Signed-off-by: Stefan Beller <sbeller@google.com>
---
* only renaming, no extra code in this patch.
* new to the series.
refs.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/refs.c b/refs.c
index f0f0d23..58de60c 100644
--- a/refs.c
+++ b/refs.c
@@ -3554,7 +3554,7 @@ enum transaction_state {
* as atomically as possible. This structure is opaque to callers.
*/
struct transaction {
- struct ref_update **updates;
+ struct ref_update **ref_updates;
size_t alloc;
size_t nr;
enum transaction_state state;
@@ -3575,10 +3575,10 @@ void transaction_free(struct transaction *transaction)
return;
for (i = 0; i < transaction->nr; i++) {
- free(transaction->updates[i]->msg);
- free(transaction->updates[i]);
+ free(transaction->ref_updates[i]->msg);
+ free(transaction->ref_updates[i]);
}
- free(transaction->updates);
+ free(transaction->ref_updates);
free(transaction);
}
@@ -3589,8 +3589,8 @@ static struct ref_update *add_update(struct transaction *transaction,
struct ref_update *update = xcalloc(1, sizeof(*update) + len + 1);
strcpy((char *)update->refname, refname);
- ALLOC_GROW(transaction->updates, transaction->nr + 1, transaction->alloc);
- transaction->updates[transaction->nr++] = update;
+ ALLOC_GROW(transaction->ref_updates, transaction->nr + 1, transaction->alloc);
+ transaction->ref_updates[transaction->nr++] = update;
return update;
}
@@ -3712,7 +3712,7 @@ int transaction_commit(struct transaction *transaction,
int ret = 0, delnum = 0, i;
const char **delnames;
int n = transaction->nr;
- struct ref_update **updates = transaction->updates;
+ struct ref_update **updates = transaction->ref_updates;
assert(err);
--
2.2.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/4] refs.c: add a transaction function to append a reflog entry
2014-12-02 7:46 [PATCHv2 0/4] refs.c: use transactions for the reflog Stefan Beller
2014-12-02 7:46 ` [PATCH 1/4] refs.c: rename the transaction functions Stefan Beller
2014-12-02 7:46 ` [PATCH 2/4] refs.c: rename transaction.updates to transaction.ref_updates Stefan Beller
@ 2014-12-02 7:46 ` Stefan Beller
2014-12-03 3:15 ` Jonathan Nieder
2014-12-02 7:46 ` [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire Stefan Beller
2014-12-03 18:05 ` [PATCHv2 0/4] refs.c: use transactions for the reflog Junio C Hamano
4 siblings, 1 reply; 14+ messages in thread
From: Stefan Beller @ 2014-12-02 7:46 UTC (permalink / raw)
To: gitster, git, ronniesahlberg, mhagger, jrnieder
Cc: Stefan Beller, Ronnie Sahlberg
When performing a reflog transaction update, only write to the reflog iff
msg is non-NULL. This can then be combined with REFLOG_TRUNCATE to perform
an update that only truncates but does not write. This change only affects
whether or not a reflog entry should be generated and written. If msg == NULL
then no such entry will be written.
Orthogonal to this we have a boolean flag REFLOG_TRUNCATE which is used to
tell the transaction system to "truncate the reflog and thus discard all
previous users".
At the current time the only place where we use msg == NULL is also the
place, where we use REFLOG_TRUNCATE. Even though these two settings are
currently only ever used together it still makes sense to have them through
two separate knobs.
This allows future consumers of this API that may want to do things
differently. For example someone can do:
msg="Reflog truncated by Bob because ..." + REFLOG_TRUNCATE
and have it truncate the log and have it start fresh with an initial message
that explains the log was truncated. This API allows that.
During one transaction we allow to make multiple reflog updates to the
same ref. This means we only need to lock the reflog once, during the first
update that touches the reflog, and that all further updates can just write the
reflog entry since the reflog is already locked.
This allows us to write code such as:
t = transaction_begin()
transaction_reflog_update(t, "foo", REFLOG_TRUNCATE, NULL);
loop-over-something...
transaction_reflog_update(t, "foo", 0, <message>);
transaction_commit(t)
where we first truncate the reflog and then build the new content one line
at a time.
Signed-off-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
This is a complete rewrite of the patch you would have found earlier on
the list. The approach was changed to deal with the reflogs differently
and not toss them into the array containing all the ref_updates, but
keep them in a separate string list.
As I am borrowing some text for the commit message and some ideas how to approach
the problem, I still added Ronnies sign off.
refs.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
refs.h | 21 +++++++++++
2 files changed, 146 insertions(+), 2 deletions(-)
diff --git a/refs.c b/refs.c
index 58de60c..2861486 100644
--- a/refs.c
+++ b/refs.c
@@ -3557,6 +3557,12 @@ struct transaction {
struct ref_update **ref_updates;
size_t alloc;
size_t nr;
+
+ /*
+ * Sorted list of reflogs to be committed,
+ * the util points to the lock_file
+ */
+ struct string_list reflog_updates;
enum transaction_state state;
};
@@ -3564,7 +3570,10 @@ struct transaction *transaction_begin(struct strbuf *err)
{
assert(err);
- return xcalloc(1, sizeof(struct transaction));
+ struct transaction *ret = xcalloc(1, sizeof(struct transaction));
+ string_list_init(&ret->reflog_updates, 1);
+
+ return ret;
}
void transaction_free(struct transaction *transaction)
@@ -3629,6 +3638,112 @@ int transaction_update_ref(struct transaction *transaction,
return 0;
}
+/* Returns a fd, -1 on error. */
+static int get_reflog_updates_fd(struct transaction *transaction,
+ const char *refname,
+ struct strbuf *err)
+{
+ char *path;
+ struct lock_file *lock;
+ struct string_list_item *item = string_list_insert(
+ &transaction->reflog_updates,
+ refname);
+ if (!item->util) {
+ item->util = xcalloc(1, sizeof(struct lock_file));
+ lock = item->util;
+ path = git_path("logs/locks/%s", refname);
+ if (safe_create_leading_directories(path)) {
+ strbuf_addf(err,
+ "creating temporary directories %s failed.",
+ path);
+ return -1;
+ }
+
+ if (hold_lock_file_for_update(lock, path, 0) < 0) {
+ strbuf_addf(err,
+ "creating temporary file %s failed.",
+ path);
+ return -1;
+ }
+ }
+
+ lock = item->util;
+
+ return lock->fd;
+}
+
+int transaction_update_reflog(struct transaction *transaction,
+ const char *refname,
+ const unsigned char *new_sha1,
+ const unsigned char *old_sha1,
+ const char *email,
+ unsigned long timestamp, int tz,
+ const char *msg, int flags,
+ struct strbuf *err)
+{
+ /*
+ * We cannot handle reflogs the same way we handle refs because of
+ * naming conflicts in the file system.
+ *
+ * If renaming a ref from foo/foo to foo or the other way round,
+ * we need to be careful as we need the basic foo/ from being a
+ * directory to be a file or vice versa. When handling the refs
+ * this can be solved easily by first recording all we want into
+ * the packed refs file and then deleting all the loose refs. By
+ * doing it that way, we always have a valid state on disk.
+ *
+ * We don't have an equivalent of a packed refs file when dealing
+ * with reflog updates, but the API for updating the refs turned
+ * out to be conveniant, so let's introduce an intermediate file
+ * outside the $GIT_DIR/logs/refs/heads/ directory helping us
+ * avoiding this naming conflict for the reflogs. The intermediate
+ * lock file, in which we build up the new reflog will live under
+ * $GIT_DIR/logs/lock/refs/heads/ so the files
+ * $GIT_DIR/logs/lock/refs/heads/foo.lock and
+ * $GIT_DIR/logs/lock/refs/heads/foo/foo.lock
+ * do not collide.
+ */
+ struct strbuf buf = STRBUF_INIT;
+ int fd;
+
+ if (transaction->state != TRANSACTION_OPEN)
+ die("BUG: update_reflog called for transaction that is not open");
+
+ fd = get_reflog_updates_fd(transaction, refname, err);
+ if (!fd)
+ goto failure;
+
+ if (flags & REFLOG_TRUNCATE) {
+ if (lseek(fd, 0, SEEK_SET) < 0 ||
+ ftruncate(fd, 0)) {
+ strbuf_addf(err, "Could not truncate reflog: %s. %s",
+ refname, strerror(errno));
+ goto failure;
+ }
+ }
+ if (email)
+ strbuf_addf(&buf, "%s %lu %+05d", email, timestamp, tz);
+
+ if (msg &&
+ log_ref_write_fd(fd, old_sha1, new_sha1, buf.buf, msg)) {
+ strbuf_addf(err, "Could not write to reflog: %s. %s",
+ refname, strerror(errno));
+ goto failure;
+ }
+ strbuf_release(&buf);
+
+ return 0;
+failure:
+ strbuf_release(&buf);
+ /*
+ * As we are using the lock file API, any stale files left behind will
+ * be taken care of, no need to do anything here.
+ */
+
+ transaction->state = TRANSACTION_CLOSED;
+ return 1;
+}
+
int transaction_create_ref(struct transaction *transaction,
const char *refname,
const unsigned char *new_sha1,
@@ -3713,13 +3828,14 @@ int transaction_commit(struct transaction *transaction,
const char **delnames;
int n = transaction->nr;
struct ref_update **updates = transaction->ref_updates;
+ struct string_list_item *item;
assert(err);
if (transaction->state != TRANSACTION_OPEN)
die("BUG: commit called for transaction that is not open");
- if (!n) {
+ if (!n && !transaction->reflog_updates.nr) {
transaction->state = TRANSACTION_CLOSED;
return 0;
}
@@ -3796,6 +3912,13 @@ int transaction_commit(struct transaction *transaction,
}
for (i = 0; i < delnum; i++)
unlink_or_warn(git_path("logs/%s", delnames[i]));
+
+ /* Commit all reflog updates*/
+ for_each_string_list_item(item, &transaction->reflog_updates) {
+ struct lock_file *lock = item->util;
+ commit_lock_file_to(lock, git_path("logs/%s", item->string));
+ }
+
clear_loose_ref_cache(&ref_cache);
cleanup:
diff --git a/refs.h b/refs.h
index 556adfd..9f70b89 100644
--- a/refs.h
+++ b/refs.h
@@ -328,6 +328,27 @@ int transaction_delete_ref(struct transaction *transaction,
struct strbuf *err);
/*
+ * Flags controlling transaction_update_reflog().
+ * REFLOG_TRUNCATE: Truncate the reflog.
+ *
+ * Flags >= 0x100 are reserved for internal use.
+ */
+#define REFLOG_TRUNCATE 0x01
+/*
+ * Append a reflog entry for refname. If the REFLOG_TRUNCATE flag is set
+ * this update will first truncate the reflog before writing the entry.
+ * If msg is NULL no update will be written to the log.
+ */
+int transaction_update_reflog(struct transaction *transaction,
+ const char *refname,
+ const unsigned char *new_sha1,
+ const unsigned char *old_sha1,
+ const char *email,
+ unsigned long timestamp, int tz,
+ const char *msg, int flags,
+ struct strbuf *err);
+
+/*
* Commit all of the changes that have been queued in transaction, as
* atomically as possible.
*
--
2.2.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire
2014-12-02 7:46 [PATCHv2 0/4] refs.c: use transactions for the reflog Stefan Beller
` (2 preceding siblings ...)
2014-12-02 7:46 ` [PATCH 3/4] refs.c: add a transaction function to append a reflog entry Stefan Beller
@ 2014-12-02 7:46 ` Stefan Beller
2014-12-03 3:18 ` Jonathan Nieder
2014-12-03 18:05 ` [PATCHv2 0/4] refs.c: use transactions for the reflog Junio C Hamano
4 siblings, 1 reply; 14+ messages in thread
From: Stefan Beller @ 2014-12-02 7:46 UTC (permalink / raw)
To: gitster, git, ronniesahlberg, mhagger, jrnieder
Cc: Ronnie Sahlberg, Stefan Beller
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>
---
no changes since sending it 5 days ago.
builtin/reflog.c | 86 ++++++++++++++++++++++++--------------------------------
1 file changed, 37 insertions(+), 49 deletions(-)
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 2d85d26..55f3023 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,
@@ -290,7 +291,7 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig
static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
const char *email, unsigned long timestamp, int tz,
- const char *message, void *cb_data)
+ const char *message, void *cb_data, struct strbuf *err)
{
struct expire_reflog_cb *cb = cb_data;
struct commit *old, *new;
@@ -316,20 +317,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, 0,
+ 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 +352,27 @@ 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;
- /*
- * 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_update_reflog(cb.t, cb.refname, null_sha1, null_sha1,
+ NULL, 0, 0, NULL, REFLOG_TRUNCATE,
+ &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
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/4] refs.c: rename the transaction functions
2014-12-02 7:46 ` [PATCH 1/4] refs.c: rename the transaction functions Stefan Beller
@ 2014-12-03 2:24 ` Jonathan Nieder
0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Nieder @ 2014-12-03 2:24 UTC (permalink / raw)
To: Stefan Beller; +Cc: gitster, git, ronniesahlberg, mhagger, Ronnie Sahlberg
Stefan Beller wrote:
> No changes since sending it 5 days ago.
>
> branch.c | 13 +++++----
> builtin/commit.c | 10 +++----
> builtin/fetch.c | 12 ++++----
> builtin/receive-pack.c | 13 ++++-----
> builtin/replace.c | 10 +++----
> builtin/tag.c | 10 +++----
> builtin/update-ref.c | 26 ++++++++---------
> fast-import.c | 22 +++++++-------
> refs.c | 78 +++++++++++++++++++++++++-------------------------
> refs.h | 36 +++++++++++------------
> sequencer.c | 12 ++++----
> walker.c | 10 +++----
> 12 files changed, 126 insertions(+), 126 deletions(-)
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 2/4] refs.c: rename transaction.updates to transaction.ref_updates
2014-12-02 7:46 ` [PATCH 2/4] refs.c: rename transaction.updates to transaction.ref_updates Stefan Beller
@ 2014-12-03 2:43 ` Jonathan Nieder
0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Nieder @ 2014-12-03 2:43 UTC (permalink / raw)
To: Stefan Beller; +Cc: gitster, git, ronniesahlberg, mhagger
Stefan Beller wrote:
> The updates are only holding refs not reflogs, so express it to the reader.
>
> Signed-off-by: Stefan Beller <sbeller@google.com>
> ---
> refs.c | 14 +++++++-------
> 1 file changed, 7 insertions(+), 7 deletions(-)
Makes sense.
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] refs.c: add a transaction function to append a reflog entry
2014-12-02 7:46 ` [PATCH 3/4] refs.c: add a transaction function to append a reflog entry Stefan Beller
@ 2014-12-03 3:15 ` Jonathan Nieder
2014-12-03 22:28 ` Stefan Beller
0 siblings, 1 reply; 14+ messages in thread
From: Jonathan Nieder @ 2014-12-03 3:15 UTC (permalink / raw)
To: Stefan Beller; +Cc: gitster, git, ronniesahlberg, mhagger
Stefan Beller wrote:
> When performing a reflog transaction update, only write to the reflog iff
> msg is non-NULL. This can then be combined with REFLOG_TRUNCATE to perform
> an update that only truncates but does not write. This change only affects
> whether or not a reflog entry should be generated and written. If msg == NULL
> then no such entry will be written.
>
> Orthogonal to this we have a boolean flag REFLOG_TRUNCATE which is used to
> tell the transaction system to "truncate the reflog and thus discard all
> previous users".
>
> At the current time the only place where we use msg == NULL is also the
> place, where we use REFLOG_TRUNCATE. Even though these two settings are
> currently only ever used together it still makes sense to have them through
> two separate knobs.
>
> This allows future consumers of this API that may want to do things
> differently. For example someone can do:
> msg="Reflog truncated by Bob because ..." + REFLOG_TRUNCATE
> and have it truncate the log and have it start fresh with an initial message
> that explains the log was truncated. This API allows that.
>
> During one transaction we allow to make multiple reflog updates to the
> same ref. This means we only need to lock the reflog once, during the first
> update that touches the reflog, and that all further updates can just write the
> reflog entry since the reflog is already locked.
I'm having trouble parsing all of the above. Can you explain the
motivation of the patch in a sentence or so? Afterward that, if the
API is not self-explanatory, there could be a short explanation of it
(e.g., a list of functions and how they get used).
[...]
> --- a/refs.c
> +++ b/refs.c
> @@ -3557,6 +3557,12 @@ struct transaction {
> struct ref_update **ref_updates;
> size_t alloc;
> size_t nr;
> +
> + /*
> + * Sorted list of reflogs to be committed,
> + * the util points to the lock_file
> + */
> + struct string_list reflog_updates;
Grammar nit: where there is a comma here, there should be the end of a
sentence.
[...]
> @@ -3564,7 +3570,10 @@ struct transaction *transaction_begin(struct strbuf *err)
> {
> assert(err);
>
> - return xcalloc(1, sizeof(struct transaction));
> + struct transaction *ret = xcalloc(1, sizeof(struct transaction));
> + string_list_init(&ret->reflog_updates, 1);
Can do
ret->reflog_updates.strdup_strings = 1;
instead, since calloc already zeroed the memory.
[...]
> +/* Returns a fd, -1 on error. */
> +static int get_reflog_updates_fd(struct transaction *transaction,
> + const char *refname,
> + struct strbuf *err)
> +{
> + char *path;
> + struct lock_file *lock;
> + struct string_list_item *item = string_list_insert(
> + &transaction->reflog_updates,
> + refname);
> + if (!item->util) {
It can be clearer to handle the simple case first:
if (item->util) {
lock = item->util;
return lock->fd;
}
item->util = xcalloc(...);
> + item->util = xcalloc(1, sizeof(struct lock_file));
> + lock = item->util;
> + path = git_path("logs/locks/%s", refname);
> + if (safe_create_leading_directories(path)) {
> + strbuf_addf(err,
> + "creating temporary directories %s failed.",
> + path);
Looking at other callers, looks like something like
if (scld(path)) {
strbuf_addf(err, "could not create leading directories of '%s': %s",
path, strerror(errno));
is common. That way, the message includes details from errno, it's
clear that one of the leading directories to $path, not $path itself,
was what could not be created, and there is no trailing '.' at the end
of the message.
> + if (hold_lock_file_for_update(lock, path, 0) < 0) {
> + strbuf_addf(err,
> + "creating temporary file %s failed.",
> + path);
hold_lock_file_for_update() is weird and has its own special error
message writing function:
unable_to_lock_message(path, errno, err);
That lets it give advice to the user about why writing the .lock
file failed and how to fix it.
I have a series that simplifies by making it write directly to a
strbuf passed as an argument, but that's orthogonal to this patch.
[...]
> +int transaction_update_reflog(struct transaction *transaction,
> + const char *refname,
> + const unsigned char *new_sha1,
> + const unsigned char *old_sha1,
> + const char *email,
> + unsigned long timestamp, int tz,
> + const char *msg, int flags,
> + struct strbuf *err)
This is an intimidating list of arguments. Would it make sense to
pack them into a struct, or to make the list less intimidating
some other way (e.g. combining email + timestamp + tz into an
ident string)?
[...]
> + fd = get_reflog_updates_fd(transaction, refname, err);
> + if (!fd)
> + goto failure;
if (fd < 0)
[...]
> + if (flags & REFLOG_TRUNCATE) {
> + if (lseek(fd, 0, SEEK_SET) < 0 ||
> + ftruncate(fd, 0)) {
> + strbuf_addf(err, "Could not truncate reflog: %s. %s",
> + refname, strerror(errno));
Odd error message format (using '.' to separate the refname from
strerror(errno) is unusual). Errors normally are supposed to start
with a lowercase letter, like
cannot truncate reflog '%s': %s
> + goto failure;
> + }
> + }
How does this cause the reflog to be populated in the !(flags &
REFLOG_TRUNCATE) case?
Maybe I am misunderstanding the API. If I use
transaction_update_reflog() and have not updated the reflog
previously, isn't this supposed to just append a new entry to the
reflog?
[...]
> +failure:
> + strbuf_release(&buf);
> + /*
> + * As we are using the lock file API, any stale files left behind will
> + * be taken care of, no need to do anything here.
> + */
That's only true if the caller is going to exit instead of proceeding
to other work.
With current callers, I assume that's true. So should this comment
say something like "No need to roll back stale lock files because
the caller will exit soon"? Or should this roll back the lockfile
anyway, in case the caller wants to try again?
> +
> + transaction->state = TRANSACTION_CLOSED;
> + return 1;
The normal convention is -1 on error.
[...]
> @@ -3796,6 +3912,13 @@ int transaction_commit(struct transaction *transaction,
> }
> for (i = 0; i < delnum; i++)
> unlink_or_warn(git_path("logs/%s", delnames[i]));
> +
> + /* Commit all reflog updates*/
> + for_each_string_list_item(item, &transaction->reflog_updates) {
> + struct lock_file *lock = item->util;
> + commit_lock_file_to(lock, git_path("logs/%s", item->string));
Neat.
This seems like a good starting point. Other code paths still write
to reflogs directly --- is there a plan to get them to use this code,
too, in a followup patch (e.g., by making write_ref_sha1() or
log_ref_write() use its own small transaction for the reflog update)?
Thanks and hope that helps,
Jonathan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire
2014-12-02 7:46 ` [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire Stefan Beller
@ 2014-12-03 3:18 ` Jonathan Nieder
0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Nieder @ 2014-12-03 3:18 UTC (permalink / raw)
To: Stefan Beller; +Cc: gitster, git, ronniesahlberg, mhagger, Ronnie Sahlberg
Stefan Beller wrote:
> --- a/builtin/reflog.c
> +++ b/builtin/reflog.c
[...]
> @@ -290,7 +291,7 @@ static int unreachable(struct expire_reflog_cb *cb, struct commit *commit, unsig
>
> static int expire_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
> const char *email, unsigned long timestamp, int tz,
> - const char *message, void *cb_data)
> + const char *message, void *cb_data, struct strbuf *err)
This doesn't match the signature of each_reflog_ent_fn. Would putting
err in the cb_data struct work?
Curious,
Jonathan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCHv2 0/4] refs.c: use transactions for the reflog
2014-12-02 7:46 [PATCHv2 0/4] refs.c: use transactions for the reflog Stefan Beller
` (3 preceding siblings ...)
2014-12-02 7:46 ` [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire Stefan Beller
@ 2014-12-03 18:05 ` Junio C Hamano
4 siblings, 0 replies; 14+ messages in thread
From: Junio C Hamano @ 2014-12-03 18:05 UTC (permalink / raw)
To: Stefan Beller; +Cc: git, ronniesahlberg, mhagger, jrnieder
Stefan Beller <sbeller@google.com> writes:
> This is the core part of the refs-transactions-reflog series[1],
> which was in discussion for a bit already.
I think what 3/4 attempts to do is very sensible, but I agree with
Jonathan that it needs a bit more polishing.
Am planning to queue only the first two for today's integration
cycle on 'pu'. Thanks.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] refs.c: add a transaction function to append a reflog entry
2014-12-03 3:15 ` Jonathan Nieder
@ 2014-12-03 22:28 ` Stefan Beller
2014-12-03 22:52 ` Jonathan Nieder
0 siblings, 1 reply; 14+ messages in thread
From: Stefan Beller @ 2014-12-03 22:28 UTC (permalink / raw)
To: Jonathan Nieder; +Cc: gitster, git, ronniesahlberg, mhagger
On Tue, Dec 02, 2014 at 07:15:19PM -0800, Jonathan Nieder wrote:
I'll think about rewriting the commit message, so it is easier to digest.
I'll follow your suggestions except for the following annotations
>
> > +int transaction_update_reflog(struct transaction *transaction,
> > + const char *refname,
> > + const unsigned char *new_sha1,
> > + const unsigned char *old_sha1,
> > + const char *email,
> > + unsigned long timestamp, int tz,
> > + const char *msg, int flags,
> > + struct strbuf *err)
>
> This is an intimidating list of arguments. Would it make sense to
> pack them into a struct, or to make the list less intimidating
> some other way (e.g. combining email + timestamp + tz into an
> ident string)?
It's true, that is's a huge list. One of the reasons Ronnie gave,
was having symmetry in reflog.c:expire_reflog_ent, which has a very
similar signature, the email + timestamp + tz are passed in as separate
arguments.
expire_reflog_ent is being called from within reflog.c:expire_reflog
if (for_each_reflog_ent(ref, expire_reflog_ent, &cb)) {
status |= error("%s", err.buf);
goto cleanup;
}
now if, we dive into the for_each_reflog_ent function, it's essentially
just calling show_one_reflog_ent on each reflog entry.
In there we are trying to separate a reflogs entry into the fields
(new sha1, old sha1, committer, email, time, timezone, message) by the
lovely expression
/* old SP new SP name <email> SP time TAB msg LF */
if (sb->len < 83 || sb->buf[sb->len - 1] != '\n' ||
get_sha1_hex(sb->buf, osha1) || sb->buf[40] != ' ' ||
get_sha1_hex(sb->buf + 41, nsha1) || sb->buf[81] != ' ' ||
!(email_end = strchr(sb->buf + 82, '>')) ||
email_end[1] != ' ' ||
!(timestamp = strtoul(email_end + 2, &message, 10)) ||
!message || message[0] != ' ' ||
(message[1] != '+' && message[1] != '-') ||
!isdigit(message[2]) || !isdigit(message[3]) ||
!isdigit(message[4]) || !isdigit(message[5]))
return 0; /* corrupt? */
so I wonder if it actually makes sense to first separate it out into fields,
and then joining to an ident string again. Is there some kind of struct already,
which groups together identifying information, such as name, email, timestamp + zone,
which could be reused here for passing on the data?
Anyway, this is a first step on transactioning the reflog code, so it is minimally
invasive, not changing a lot of business logic. If you look into the next patch,
(reflog.c: use a reflog transaction when writing during expire)
you'll see that it's essentially just a replacement of printfs to calling
the function.
- if (cb->newlog) {
- 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, 0,
+ cb->err))
and the errorhandling was removed.
If we want to change the function signature of transaction_update_reflog,
I'd do it in a follow up?
>
>
> [...]
> > + if (flags & REFLOG_TRUNCATE) {
> > + if (lseek(fd, 0, SEEK_SET) < 0 ||
> > + ftruncate(fd, 0)) {
> > + strbuf_addf(err, "Could not truncate reflog: %s. %s",
> > + refname, strerror(errno));
>
> Odd error message format (using '.' to separate the refname from
> strerror(errno) is unusual). Errors normally are supposed to start
> with a lowercase letter, like
>
> cannot truncate reflog '%s': %s
>
> > + goto failure;
> > + }
> > + }
>
> How does this cause the reflog to be populated in the !(flags &
> REFLOG_TRUNCATE) case?
>
> Maybe I am misunderstanding the API. If I use
> transaction_update_reflog() and have not updated the reflog
> previously, isn't this supposed to just append a new entry to the
> reflog?
>
He, that's indeed a good catch. I was investigating the API again myself and
the REFLOG_TRUNCATE flag is only set on the very first call to transaction_update_reflog
and the subsequent calls are rebuilding the reflog by adding the unpruned lines
again line by line.
I am wondering if we should actually put that into the same function now.
As the new reflog is build on the calls by transaction_update_reflog, it's actually
depending on the order strictly as opposed to the refs.
Maybe we want to have two separate functions
transaction_update_begin_reflog(...)
transaction_update_reflog_add_line(...)
instead? Then a reflog update could look like this:
t=transaction_begin(...)
transaction_update_begin_reflog(t, refname)
for_each_reflog_entry_for_refname(entry, refname):
if (want_to_keep(entry):
transaction_update_reflog_add_line(entry, refname)
transaction_commit(...)
The logic of want_to_keep is currently in reflog.c:expire_reflog_ent(...),
not sure if there are other places.
> [...]
> > +failure:
> > + strbuf_release(&buf);
> > + /*
> > + * As we are using the lock file API, any stale files left behind will
> > + * be taken care of, no need to do anything here.
> > + */
>
> That's only true if the caller is going to exit instead of proceeding
> to other work.
>
> With current callers, I assume that's true. So should this comment
> say something like "No need to roll back stale lock files because
> the caller will exit soon"? Or should this roll back the lockfile
> anyway, in case the caller wants to try again?
I am not sure if we ever want transactions be tried again without the user
explicitely rerunning the command?
As we're operating on a lockfile, which was just created by us, and now in
the failure command, we're likely to die? Maybe I remove the comment altogether,
as the wondering reader will look into the API for lock files, when looking
for problems here.
> > + /* Commit all reflog updates*/
> > + for_each_string_list_item(item, &transaction->reflog_updates) {
> > + struct lock_file *lock = item->util;
> > + commit_lock_file_to(lock, git_path("logs/%s", item->string));
>
> Neat.
>
> This seems like a good starting point. Other code paths still write
> to reflogs directly --- is there a plan to get them to use this code,
> too, in a followup patch (e.g., by making write_ref_sha1() or
> log_ref_write() use its own small transaction for the reflog update)?
>
That's the plan, but not part of this patch series yet.
> Thanks and hope that helps,
> Jonathan
Thanks for the comments,
Stefan
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] refs.c: add a transaction function to append a reflog entry
2014-12-03 22:28 ` Stefan Beller
@ 2014-12-03 22:52 ` Jonathan Nieder
0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Nieder @ 2014-12-03 22:52 UTC (permalink / raw)
To: Stefan Beller; +Cc: gitster, git, ronniesahlberg, mhagger
Stefan Beller wrote:
> On Tue, Dec 02, 2014 at 07:15:19PM -0800, Jonathan Nieder wrote:
>> Stefan Beller wrote:
>>> +int transaction_update_reflog(struct transaction *transaction,
>>> + const char *refname,
>>> + const unsigned char *new_sha1,
>>> + const unsigned char *old_sha1,
>>> + const char *email,
>>> + unsigned long timestamp, int tz,
>>> + const char *msg, int flags,
>>> + struct strbuf *err)
>>
>> This is an intimidating list of arguments. Would it make sense to
>> pack them into a struct, or to make the list less intimidating
>> some other way (e.g. combining email + timestamp + tz into an
>> ident string)?
>
> It's true, that is's a huge list.
[...]
> If we want to change the function signature of transaction_update_reflog,
> I'd do it in a follow up?
The important change here is that it is moving from a static to a public
function. In static functions, having a signature that is hard to work
with is okay because the possibility of confusion is restricted to
callers coordinating between each other in the same file. Now that the
function is becoming public, it is time to think about the API.
[...]
>> Maybe I am misunderstanding the API. If I use
>> transaction_update_reflog() and have not updated the reflog
>> previously, isn't this supposed to just append a new entry to the
>> reflog?
>
> He, that's indeed a good catch. I was investigating the API again myself and
> the REFLOG_TRUNCATE flag is only set on the very first call to transaction_update_reflog
> and the subsequent calls are rebuilding the reflog by adding the unpruned lines
> again line by line.
Taking a step back, there are two ways this API can be used:
* commands like "git reflog expire" that filter the reflog want to
create an entirely new reflog and copy entries one by one into it
* commands like "git update-ref" that append to the reflog want to
have the reflog as-is, plus some new entries added one-by-one
For that second use, the only operation needed is
transaction_update_reflog
which would add a line to the reflog. The first use can have that plus
transaction_truncate_reflog
which would clear the reflog.
If I understood the API proposed by Ronnie, it combined those two
operations into a single function, transaction_truncate_reflog(flag).
The flag could be REFLOG_TRUNCATE to mean "truncate the reflog first",
analagous to the O_TRUNC flag in open(2).
Either API (the two-function version with no flag or one-function
version with flag) is basically equivalent --- they can be implemented
in terms of each other. I slightly prefer the two-function API since
it makes the sequence of operations more obvious ("first truncate,
then append this, then append that, then...").
[...]
>>> +failure:
>>> + strbuf_release(&buf);
>>> + /*
>>> + * As we are using the lock file API, any stale files left behind will
>>> + * be taken care of, no need to do anything here.
>>> + */
>>
>> That's only true if the caller is going to exit instead of proceeding
>> to other work.
>>
>> With current callers, I assume that's true. So should this comment
>> say something like "No need to roll back stale lock files because
>> the caller will exit soon"? Or should this roll back the lockfile
>> anyway, in case the caller wants to try again?
>
> I am not sure if we ever want transactions be tried again without the user
> explicitely rerunning the command?
>
> As we're operating on a lockfile, which was just created by us, and now in
> the failure command, we're likely to die? Maybe I remove the comment altogether,
> as the wondering reader will look into the API for lock files, when looking
> for problems here.
It is tempting to roll back the lock file and keeping the transaction in OPEN
state would be best. That way, the caller can keep going if they want
to --- it is as if the failing call never happened.
... except that rolling back the lockfile would mean rolling back previous
updates to the same reflog that had succeeded, too.
So I think closing the transaction like you do is the right thing to
do. Rolling back the lockfile wouldn't be useful since there are
still other lockfiles to take care of from previous updates to other
reflogs that haven't been rolled back. The comment should say that
the caller is going to exit.
Thanks,
Jonathan
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2014-12-03 22:52 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-12-02 7:46 [PATCHv2 0/4] refs.c: use transactions for the reflog Stefan Beller
2014-12-02 7:46 ` [PATCH 1/4] refs.c: rename the transaction functions Stefan Beller
2014-12-03 2:24 ` Jonathan Nieder
2014-12-02 7:46 ` [PATCH 2/4] refs.c: rename transaction.updates to transaction.ref_updates Stefan Beller
2014-12-03 2:43 ` Jonathan Nieder
2014-12-02 7:46 ` [PATCH 3/4] refs.c: add a transaction function to append a reflog entry Stefan Beller
2014-12-03 3:15 ` Jonathan Nieder
2014-12-03 22:28 ` Stefan Beller
2014-12-03 22:52 ` Jonathan Nieder
2014-12-02 7:46 ` [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire Stefan Beller
2014-12-03 3:18 ` Jonathan Nieder
2014-12-03 18:05 ` [PATCHv2 0/4] refs.c: use transactions for the reflog Junio C Hamano
-- strict thread matches above, loose matches on Subject: below --
2014-12-02 2:02 [PATCH 1/4] refs.c: rename the transaction functions Stefan Beller
2014-12-02 2:02 ` [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire Stefan Beller
2014-11-20 18:17 [PATCH v3 00/14] ref-transactions-reflog Jonathan Nieder
2014-11-27 5:34 ` [PATCH 0/4] Using transactions for the reflog Stefan Beller
2014-11-27 5:34 ` [PATCH 4/4] reflog.c: use a reflog transaction when writing during expire Stefan Beller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).