Re: [PATCH v6 1/7] refs.c: add err arguments to reflog functions

2015-07-09 Thread Michael Haggerty
On 07/08/2015 07:11 PM, Junio C Hamano wrote:
 Michael Haggerty mhag...@alum.mit.edu writes:
 
 I think your v7 of this patch goes too far, by turning a failure to
 write to the reflog into a failure of the whole transaction. The problem
 is that this failure comes too late, in the commit phase of the
 transaction. Aborting at this late stage can leave some references
 changed and others rolled back, violating the promise of atomicity.
 
 Yeah, that sounds problematic.
 
 The old code reported a failure to write the reflog to stderr but didn't
 fail the transaction. I think that behavior is more appropriate. The
 reflog is of lower importance than the references themselves. Junio, do
 you agree?
 
 That is actually a loaded question.
 
 Do I agree that the current (i.e. before this change) behaviour is
 more appropriate given the current choice of representation of refs
 and reflogs on the filesystem, treating a failure to update reflog
 as lower importance event and accept it as a limitation that it
 cannot abort the whole transaction atomically?  Compared to leaving
 the repository in a half-updated state where some refs and their
 logs are updated already, other remaining proposed updates are
 ignored, and the transaction claims to have failed even though some
 things have already changed and we cannot rollback, I would say that
 is a better compromise to treat reflog update as a lower importance.
 
 Do I agree that reflog writing should stay to be best-effort in the
 longer term?  Not really.  If we are moving the ref API in the
 direction where we can plug a backend that is different from the
 traditional filesystem based one for storing refs, I think the
 backend should also be responsible for storing logs for the refs it
 stores, and if the backend wants to promise atomicity, then we
 should be able to fail the whole transaction when updates to refs
 could proceed but updates to the log of one of these updated refs
 cannot.  So I do not agree to cast in stone the reflog is of lower
 importance as a general rule.

Junio,

You make a good distinction. I was describing a compromise that we have
to make now due to the limitations of the current ref/reflog backend.
But I agree 100% that a future storage backend that can do correct
rollback of refs *and* reflogs can fail a transaction if the reflog
updates cannot be committed.

Thanks,
Michael

-- 
Michael Haggerty
mhag...@alum.mit.edu

--
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


Re: [PATCH v6 1/7] refs.c: add err arguments to reflog functions

2015-07-08 Thread Michael Haggerty
On 07/08/2015 12:41 AM, David Turner wrote:
 On Mon, 2015-07-06 at 17:53 +0200, Michael Haggerty wrote:
 On 06/29/2015 10:17 PM, David Turner wrote:
 [...]
 @@ -3317,7 +3322,8 @@ static int commit_ref_update(struct ref_lock *lock,
   head_sha1, head_flag);
 if (head_ref  (head_flag  REF_ISSYMREF) 
 !strcmp(head_ref, lock-ref_name))
 -   log_ref_write(HEAD, lock-old_oid.hash, sha1, logmsg);
 +   log_ref_write(HEAD, lock-old_oid.hash, sha1, logmsg,
 + err);

 Here you don't check for errors from log_ref_write(). So it might or
 might not have written something to err. If it has, is that error
 handled correctly?
 
 That was the case before this patch too. But I guess I might as well
 check.

This isn't about fixing a pre-existing bug. Your patch introduced a
regression.

Before this patch, commit_ref_update() didn't really need to know
whether log_ref_write() failed, because it didn't take any further
remedial action anyway. log_ref_write() would have already written an
error message to stderr, and that was all the error handling that was
needed.

But now, log_ref_write() *doesn't* write its error message to stderr; it
only stores it to `err`. So now it is the caller's responsibility to
check whether there was an error, and if so write `err` to stderr.
Otherwise the error message will get lost entirely, I think.

I think your v7 of this patch goes too far, by turning a failure to
write to the reflog into a failure of the whole transaction. The problem
is that this failure comes too late, in the commit phase of the
transaction. Aborting at this late stage can leave some references
changed and others rolled back, violating the promise of atomicity.

The old code reported a failure to write the reflog to stderr but didn't
fail the transaction. I think that behavior is more appropriate. The
reflog is of lower importance than the references themselves. Junio, do
you agree?

If so, it might be that adding err arguments to the reflog functions
does not bring any benefits.

Michael

-- 
Michael Haggerty
mhag...@alum.mit.edu

--
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


Re: [PATCH v6 1/7] refs.c: add err arguments to reflog functions

2015-07-08 Thread Junio C Hamano
Michael Haggerty mhag...@alum.mit.edu writes:

 I think your v7 of this patch goes too far, by turning a failure to
 write to the reflog into a failure of the whole transaction. The problem
 is that this failure comes too late, in the commit phase of the
 transaction. Aborting at this late stage can leave some references
 changed and others rolled back, violating the promise of atomicity.

Yeah, that sounds problematic.

 The old code reported a failure to write the reflog to stderr but didn't
 fail the transaction. I think that behavior is more appropriate. The
 reflog is of lower importance than the references themselves. Junio, do
 you agree?

That is actually a loaded question.

Do I agree that the current (i.e. before this change) behaviour is
more appropriate given the current choice of representation of refs
and reflogs on the filesystem, treating a failure to update reflog
as lower importance event and accept it as a limitation that it
cannot abort the whole transaction atomically?  Compared to leaving
the repository in a half-updated state where some refs and their
logs are updated already, other remaining proposed updates are
ignored, and the transaction claims to have failed even though some
things have already changed and we cannot rollback, I would say that
is a better compromise to treat reflog update as a lower importance.

Do I agree that reflog writing should stay to be best-effort in the
longer term?  Not really.  If we are moving the ref API in the
direction where we can plug a backend that is different from the
traditional filesystem based one for storing refs, I think the
backend should also be responsible for storing logs for the refs it
stores, and if the backend wants to promise atomicity, then we
should be able to fail the whole transaction when updates to refs
could proceed but updates to the log of one of these updated refs
cannot.  So I do not agree to cast in stone the reflog is of lower
importance as a general rule.

--
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


Re: [PATCH v6 1/7] refs.c: add err arguments to reflog functions

2015-07-07 Thread David Turner
On Mon, 2015-07-06 at 17:53 +0200, Michael Haggerty wrote:
 On 06/29/2015 10:17 PM, David Turner wrote:
  Add an err argument to log_ref_setup that can explain the reason
  for a failure. This then eliminates the need to manage errno through
  this function since we can just add strerror(errno) to the err string
  when meaningful. No callers relied on errno from this function for
  anything else than the error message.
  
  Also add err arguments to private functions write_ref_to_lockfile,
  log_ref_write_1, commit_ref_update. This again eliminates the need to
  manage errno in these functions.
  
  Update of a patch by Ronnie Sahlberg.
 
 First a general comment: we have a convention, not yet very well adhered
 to, that error messages should start with lower-case letters. I know
 that in many cases you are just carrying along pre-existing error
 messages that are capitalized. But at a minimum, please avoid adding new
 error messages that are capitalized. And if you are feeling ambitious,
 feel free to lower-case some existing ones :-)

I'll save lowercasing messages for other patches, but I'll try to take
care with new messages.

...

 Above, the call to close(logfd) could clobber errno. It would be better
 to exchange the calls.

Done, thanks.

 Since you are passing err into log_ref_write(), I assume that it would
 already have an error message written to it by the time you enter into
 this block. Yet in the block you append more text to it.
 
 It seems to me that you either want to clear err and replace it with
 your own message, or create a new message that looks like
 
 Cannot update the ref '%s': %s
 
 where the second %s is replaced with the error from log_ref_write().

Done, thanks.

  @@ -3317,7 +3322,8 @@ static int commit_ref_update(struct ref_lock *lock,
head_sha1, head_flag);
  if (head_ref  (head_flag  REF_ISSYMREF) 
  !strcmp(head_ref, lock-ref_name))
  -   log_ref_write(HEAD, lock-old_oid.hash, sha1, logmsg);
  +   log_ref_write(HEAD, lock-old_oid.hash, sha1, logmsg,
  + err);
 
 Here you don't check for errors from log_ref_write(). So it might or
 might not have written something to err. If it has, is that error
 handled correctly?

That was the case before this patch too. But I guess I might as well
check.

 Previously, the error generated here was cannot update the ref '%s'.
 But now that you are letting write_ref_to_lockfile() fill err, the error
 message will be something from that function. This might be OK or it
 might not. If you think it is, it would be worth a word or two of
 justification in the commit message.

Will adjust commit message.

--
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


Re: [PATCH v6 1/7] refs.c: add err arguments to reflog functions

2015-07-06 Thread Michael Haggerty
On 06/29/2015 10:17 PM, David Turner wrote:
 Add an err argument to log_ref_setup that can explain the reason
 for a failure. This then eliminates the need to manage errno through
 this function since we can just add strerror(errno) to the err string
 when meaningful. No callers relied on errno from this function for
 anything else than the error message.
 
 Also add err arguments to private functions write_ref_to_lockfile,
 log_ref_write_1, commit_ref_update. This again eliminates the need to
 manage errno in these functions.
 
 Update of a patch by Ronnie Sahlberg.

First a general comment: we have a convention, not yet very well adhered
to, that error messages should start with lower-case letters. I know
that in many cases you are just carrying along pre-existing error
messages that are capitalized. But at a minimum, please avoid adding new
error messages that are capitalized. And if you are feeling ambitious,
feel free to lower-case some existing ones :-)

 Signed-off-by: Ronnie Sahlberg sahlb...@google.com
 Signed-off-by: David Turner dtur...@twopensource.com
 ---
  builtin/checkout.c |   8 ++--
  refs.c | 111 
 -
  refs.h |   4 +-
  3 files changed, 66 insertions(+), 57 deletions(-)
 
 diff --git a/builtin/checkout.c b/builtin/checkout.c
 [...]
 diff --git a/refs.c b/refs.c
 index fb568d7..c97ca02 100644
 --- a/refs.c
 +++ b/refs.c
 [...]
 @@ -3216,26 +3217,25 @@ static int log_ref_write_1(const char *refname, const 
 unsigned char *old_sha1,
   result = log_ref_write_fd(logfd, old_sha1, new_sha1,
 git_committer_info(0), msg);
   if (result) {
 - int save_errno = errno;
   close(logfd);
 - error(Unable to append to %s, log_file);
 - errno = save_errno;
 + strbuf_addf(err, Unable to append to %s. %s, log_file,
 + strerror(errno));
   return -1;

Above, the call to close(logfd) could clobber errno. It would be better
to exchange the calls.

   }
   if (close(logfd)) {
 - int save_errno = errno;
 - error(Unable to append to %s, log_file);
 - errno = save_errno;
 + strbuf_addf(err, Unable to append to %s. %s, log_file,
 + strerror(errno));
   return -1;
   }
   return 0;
  }
  
  static int log_ref_write(const char *refname, const unsigned char *old_sha1,
 -  const unsigned char *new_sha1, const char *msg)
 +  const unsigned char *new_sha1, const char *msg,
 +  struct strbuf *err)
  {
   struct strbuf sb = STRBUF_INIT;
 - int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, sb);
 + int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, sb, err);
   strbuf_release(sb);
   return ret;
  }
 [...]
 @@ -3288,12 +3290,15 @@ static int write_ref_to_lockfile(struct ref_lock 
 *lock,
   * necessary, using the specified lockmsg (which can be NULL).
   */
  static int commit_ref_update(struct ref_lock *lock,
 -  const unsigned char *sha1, const char *logmsg)
 +  const unsigned char *sha1, const char *logmsg,
 +  struct strbuf *err)
  {
   clear_loose_ref_cache(ref_cache);
 - if (log_ref_write(lock-ref_name, lock-old_oid.hash, sha1, logmsg)  0 
 ||
 + if (log_ref_write(lock-ref_name, lock-old_oid.hash, sha1, logmsg, 
 err)  0 ||
   (strcmp(lock-ref_name, lock-orig_ref_name) 
 -  log_ref_write(lock-orig_ref_name, lock-old_oid.hash, sha1, 
 logmsg)  0)) {
 +  log_ref_write(lock-orig_ref_name, lock-old_oid.hash, sha1, 
 logmsg, err)  0)) {
 + strbuf_addf(err, Cannot update the ref '%s'.,
 + lock-ref_name);
   unlock_ref(lock);
   return -1;
   }

Since you are passing err into log_ref_write(), I assume that it would
already have an error message written to it by the time you enter into
this block. Yet in the block you append more text to it.

It seems to me that you either want to clear err and replace it with
your own message, or create a new message that looks like

Cannot update the ref '%s': %s

where the second %s is replaced with the error from log_ref_write().

 @@ -3317,7 +3322,8 @@ static int commit_ref_update(struct ref_lock *lock,
 head_sha1, head_flag);
   if (head_ref  (head_flag  REF_ISSYMREF) 
   !strcmp(head_ref, lock-ref_name))
 - log_ref_write(HEAD, lock-old_oid.hash, sha1, logmsg);
 + log_ref_write(HEAD, lock-old_oid.hash, sha1, logmsg,
 +   err);

Here you don't check for errors from log_ref_write(). So it might or
might not have written something to err. If it has, is that error
handled