1. 23 6月, 2015 1 次提交
  2. 28 5月, 2015 5 次提交
  3. 26 5月, 2015 5 次提交
  4. 15 5月, 2015 1 次提交
    • M
      lock_packed_refs(): allow retries when acquiring the packed-refs lock · f4ab4f3a
      Michael Haggerty 提交于
      Currently, there is only one attempt to acquire any lockfile, and if
      the lock is held by another process, the locking attempt fails
      immediately.
      
      This is not such a limitation for loose reference files. First, they
      don't take long to rewrite. Second, most reference updates have a
      known "old" value, so if another process is updating a reference at
      the same moment that we are trying to lock it, then probably the
      expected "old" value will not longer be valid, and the update will
      fail anyway.
      
      But these arguments do not hold for packed-refs:
      
      * The packed-refs file can be large and take significant time to
        rewrite.
      
      * Many references are stored in a single packed-refs file, so it could
        be that the other process was changing a different reference than
        the one that we are interested in.
      
      Therefore, it is much more likely for there to be spurious lock
      conflicts in connection to the packed-refs file, resulting in
      unnecessary command failures.
      
      So, if the first attempt to lock the packed-refs file fails, continue
      retrying for a configurable length of time before giving up. The
      default timeout is 1 second.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      f4ab4f3a
  5. 13 5月, 2015 12 次提交
    • M
      ref_transaction_commit(): fix atomicity and avoid fd exhaustion · cf018ee0
      Michael Haggerty 提交于
      The old code was roughly
      
          for update in updates:
              acquire locks and check old_sha
          for update in updates:
              if changing value:
                  write_ref_to_lockfile()
                  commit_ref_update()
          for update in updates:
              if deleting value:
                  unlink()
          rewrite packed-refs file
          for update in updates:
              if reference still locked:
                  unlock_ref()
      
      This has two problems.
      
      Non-atomic updates
      ==================
      
      The atomicity of the reference transaction depends on all pre-checks
      being done in the first loop, before any changes have started being
      committed in the second loop. The problem is that
      write_ref_to_lockfile() (previously part of write_ref_sha1()), which
      is called from the second loop, contains two more checks:
      
      * It verifies that new_sha1 is a valid object
      
      * If the reference being updated is a branch, it verifies that
        new_sha1 points at a commit object (as opposed to a tag, tree, or
        blob).
      
      If either of these checks fails, the "transaction" is aborted during
      the second loop. But this might happen after some reference updates
      have already been permanently committed. In other words, the
      all-or-nothing promise of "git update-ref --stdin" could be violated.
      
      So these checks have to be moved to the first loop.
      
      File descriptor exhaustion
      ==========================
      
      The old code locked all of the references in the first loop, leaving
      all of the lockfiles open until later loops. Since we might be
      updating a lot of references, this could result in file descriptor
      exhaustion.
      
      The solution
      ============
      
      After this patch, the code looks like
      
          for update in updates:
              acquire locks and check old_sha
              if changing value:
                  write_ref_to_lockfile()
              else:
                  close_ref()
          for update in updates:
              if changing value:
                  commit_ref_update()
          for update in updates:
              if deleting value:
                  unlink()
          rewrite packed-refs file
          for update in updates:
              if reference still locked:
                  unlock_ref()
      
      This fixes both problems:
      
      1. The pre-checks in write_ref_to_lockfile() are now done in the first
         loop, before any changes have been committed. If any of the checks
         fails, the whole transaction can now be rolled back correctly.
      
      2. All lockfiles are closed in the first loop immediately after they
         are created (either by write_ref_to_lockfile() or by close_ref()).
         This means that there is never more than one open lockfile at a
         time, preventing file descriptor exhaustion.
      
      To simplify the bookkeeping across loops, add a new REF_NEEDS_COMMIT
      bit to update->flags, which keeps track of whether the corresponding
      lockfile needs to be committed, as opposed to just unlocked. (Since
      "struct ref_update" is internal to the refs module, this change is not
      visible to external callers.)
      
      This change fixes two tests in t1400.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      cf018ee0
    • M
      ref_transaction_commit(): remove the local flags variable · cbf50f9e
      Michael Haggerty 提交于
      Instead, work directly with update->flags. This has the advantage that
      the REF_DELETING bit, set in the first loop, can be read in the second
      loop instead of having to be recomputed. Plus, it was potentially
      confusing having both update->flags and flags, which sometimes had
      different values.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      cbf50f9e
    • M
      ref_transaction_commit(): inline call to write_ref_sha1() · 61e51e00
      Michael Haggerty 提交于
      That was the last caller, so delete function write_ref_sha1().
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      61e51e00
    • M
      rename_ref(): inline calls to write_ref_sha1() from this function · ba43b7f2
      Michael Haggerty 提交于
      Most of what it does is unneeded from these call sites.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      ba43b7f2
    • M
    • M
      write_ref_to_lockfile(): new function, extracted from write_ref_sha1() · e6fd3c67
      Michael Haggerty 提交于
      This is the first step towards separating the checking and writing of
      the new reference value to committing the change.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      e6fd3c67
    • M
      ref_transaction_commit(): fix atomicity and avoid fd exhaustion · 6c34492a
      Michael Haggerty 提交于
      The old code was roughly
      
          for update in updates:
              acquire locks and check old_sha
          for update in updates:
              if changing value:
                  write_ref_to_lockfile()
                  commit_ref_update()
          for update in updates:
              if deleting value:
                  unlink()
          rewrite packed-refs file
          for update in updates:
              if reference still locked:
                  unlock_ref()
      
      This has two problems.
      
      Non-atomic updates
      ==================
      
      The atomicity of the reference transaction depends on all pre-checks
      being done in the first loop, before any changes have started being
      committed in the second loop. The problem is that
      write_ref_to_lockfile() (previously part of write_ref_sha1()), which
      is called from the second loop, contains two more checks:
      
      * It verifies that new_sha1 is a valid object
      
      * If the reference being updated is a branch, it verifies that
        new_sha1 points at a commit object (as opposed to a tag, tree, or
        blob).
      
      If either of these checks fails, the "transaction" is aborted during
      the second loop. But this might happen after some reference updates
      have already been permanently committed. In other words, the
      all-or-nothing promise of "git update-ref --stdin" could be violated.
      
      So these checks have to be moved to the first loop.
      
      File descriptor exhaustion
      ==========================
      
      The old code locked all of the references in the first loop, leaving
      all of the lockfiles open until later loops. Since we might be
      updating a lot of references, this could result in file descriptor
      exhaustion.
      
      The solution
      ============
      
      After this patch, the code looks like
      
          for update in updates:
              acquire locks and check old_sha
              if changing value:
                  write_ref_to_lockfile()
              else:
                  close_ref()
          for update in updates:
              if changing value:
                  commit_ref_update()
          for update in updates:
              if deleting value:
                  unlink()
          rewrite packed-refs file
          for update in updates:
              if reference still locked:
                  unlock_ref()
      
      This fixes both problems:
      
      1. The pre-checks in write_ref_to_lockfile() are now done in the first
         loop, before any changes have been committed. If any of the checks
         fails, the whole transaction can now be rolled back correctly.
      
      2. All lockfiles are closed in the first loop immediately after they
         are created (either by write_ref_to_lockfile() or by close_ref()).
         This means that there is never more than one open lockfile at a
         time, preventing file descriptor exhaustion.
      
      To simplify the bookkeeping across loops, add a new REF_NEEDS_COMMIT
      bit to update->flags, which keeps track of whether the corresponding
      lockfile needs to be committed, as opposed to just unlocked. (Since
      "struct ref_update" is internal to the refs module, this change is not
      visible to external callers.)
      
      This change fixes two tests in t1400.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      6c34492a
    • M
      ref_transaction_commit(): remove the local flags variable · 805cf6e9
      Michael Haggerty 提交于
      Instead, work directly with update->flags. This has the advantage that
      the REF_DELETING bit, set in the first loop, can be read in the second
      loop instead of having to be recomputed. Plus, it was potentially
      confusing having both update->flags and flags, which sometimes had
      different values.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      805cf6e9
    • M
      ref_transaction_commit(): inline call to write_ref_sha1() · 4da50def
      Michael Haggerty 提交于
      And remove the function write_ref_sha1(), as it is no longer used.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      4da50def
    • M
      rename_ref(): inline calls to write_ref_sha1() from this function · 29957fda
      Michael Haggerty 提交于
      Most of what it does is unneeded from these call sites.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      29957fda
    • M
    • M
      write_ref_to_lockfile(): new function, extracted from write_ref_sha1() · 1d455231
      Michael Haggerty 提交于
      This is the first step towards separating the checking and writing of
      the new reference value to committing the change.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      Signed-off-by: NJunio C Hamano <gitster@pobox.com>
      1d455231
  6. 12 5月, 2015 16 次提交
    • M
      reflog_expire(): integrate lock_ref_sha1_basic() errors into ours · c628edfd
      Michael Haggerty 提交于
      Now that lock_ref_sha1_basic() gives us back its error messages via a
      strbuf, incorporate its error message into our error message rather
      than emitting two separate error messages.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      c628edfd
    • M
      ref_transaction_commit(): delete extra "the" from error message · 3553944a
      Michael Haggerty 提交于
      While we are in the area, let's remove a superfluous definite article
      from the error message that is emitted when the reference cannot be
      locked. This improves how it reads and makes it a bit shorter.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      3553944a
    • M
      ref_transaction_commit(): provide better error messages · cbaabcbc
      Michael Haggerty 提交于
      Now that lock_ref_sha1_basic() gives us back its error messages via a
      strbuf, incorporate its error message into our error message rather
      than emitting one error messages to stderr immediately and returning a
      second to our caller.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      cbaabcbc
    • M
      rename_ref(): integrate lock_ref_sha1_basic() errors into ours · abeef9c8
      Michael Haggerty 提交于
      Now that lock_ref_sha1_basic() gives us back its error messages via a
      strbuf, incorporate its error message into our error message rather
      than emitting two separate error messages.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      abeef9c8
    • M
      lock_ref_sha1_basic(): improve diagnostics for ref D/F conflicts · 5b2d8d6f
      Michael Haggerty 提交于
      If there is a failure to lock a reference that is likely caused by a
      D/F conflict (e.g., trying to lock "refs/foo/bar" when reference
      "refs/foo" already exists), invoke verify_refname_available() to try
      to generate a more helpful error message.
      
      That function might not detect an error. For example, some
      non-reference file might be blocking the deletion of an
      otherwise-empty directory tree, or there might be a race with another
      process that just deleted the offending reference. In such cases,
      generate the strerror-based error message like before.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      5b2d8d6f
    • M
      lock_ref_sha1_basic(): report errors via a "struct strbuf *err" · 4a32b2e0
      Michael Haggerty 提交于
      For now, change the callers to spew the error to stderr like before.
      But soon we will change them to incorporate the reason for the failure
      into their own error messages.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      4a32b2e0
    • M
      verify_refname_available(): report errors via a "struct strbuf *err" · 1146f17e
      Michael Haggerty 提交于
      It shouldn't be spewing errors directly to stderr.
      
      For now, change its callers to spew the errors to stderr.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      1146f17e
    • M
      verify_refname_available(): rename function · 5baf37d3
      Michael Haggerty 提交于
      Rename is_refname_available() to verify_refname_available() and change
      its return value from 1 for success to 0 for success, to be consistent
      with our error-handling convention. In a moment it will also get a
      "struct strbuf *err" parameter.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      5baf37d3
    • M
      refs: check for D/F conflicts among refs created in a transaction · e911104c
      Michael Haggerty 提交于
      If two references that D/F conflict (e.g., "refs/foo" and
      "refs/foo/bar") are created in a single transaction, the old code
      discovered the problem only after the "commit" phase of
      ref_transaction_commit() had already begun. This could leave some
      references updated and others not, which violates the promise of
      atomicity.
      
      Instead, check for such conflicts during the "locking" phase:
      
      * Teach is_refname_available() to take an "extras" parameter that can
        contain extra reference names with which the specified refname must
        not conflict.
      
      * Change lock_ref_sha1_basic() to take an "extras" parameter, which it
        passes through to is_refname_available().
      
      * Change ref_transaction_commit() to pass "affected_refnames" to
        lock_ref_sha1_basic() as its "extras" argument.
      
      This change fixes a test case in t1404.
      
      This code is a bit stricter than it needs to be. We could conceivably
      allow reference "refs/foo/bar" to be created in the same transaction
      as "refs/foo" is deleted (or vice versa). But that would be
      complicated to implement, because it is not possible to lock
      "refs/foo/bar" while "refs/foo" exists as a loose reference, but on
      the other hand we don't want to delete some references before adding
      others (because that could leave a gap during which required objects
      are unreachable). There is also a complication that reflog files'
      paths can conflict.
      
      Any less-strict implementation would probably require tricks like the
      packing of all references before the start of the real transaction, or
      the use of temporary intermediate reference names.
      
      So for now let's accept too-strict checks. Some reference update
      transactions will be rejected unnecessarily, but they will be rejected
      in their entirety rather than leaving the repository in an
      intermediate state, as would happen now.
      
      Please note that there is still one kind of D/F conflict that is *not*
      handled correctly. If two processes are running at the same time, and
      one tries to create "refs/foo" at the same time that the other tries
      to create "refs/foo/bar", then they can race with each other. Both
      processes can obtain their respective locks ("refs/foo.lock" and
      "refs/foo/bar.lock"), proceed to the "commit" phase of
      ref_transaction_commit(), and then the slower process will discover
      that it cannot rename its lockfile into place (after possibly having
      committed changes to other references). There appears to be no way to
      fix this race without changing the locking policy, which in turn would
      require a change to *all* Git clients.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      e911104c
    • M
      ref_transaction_commit(): use a string_list for detecting duplicates · 07f9c881
      Michael Haggerty 提交于
      Detect duplicates by storing the reference names in a string_list and
      sorting that, instead of sorting the ref_updates directly.
      
      * In a moment the string_list will be used for another purpose, too.
      
      * This removes the need for the custom comparison function
        ref_update_compare().
      
      * This means that we can carry out the updates in the order that the
        user specified them instead of reordering them. This might be handy
        someday if, we want to permit multiple updates to a single reference
        as long as they are compatible with each other.
      
      Note: we can't use string_list_remove_duplicates() to check for
      duplicates, because we need to know the name of the reference that
      appeared multiple times, to be used in the error message.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      07f9c881
    • M
      is_refname_available(): use dirname in first loop · 61da5969
      Michael Haggerty 提交于
      In the first loop (over prefixes of refname), use dirname to keep
      track of the current prefix. This is not an improvement in itself, but
      in a moment we will start using dirname for a role where a
      NUL-terminated string is needed.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      61da5969
    • M
      struct nonmatching_ref_data: store a refname instead of a ref_entry · 521331cc
      Michael Haggerty 提交于
      Now that we don't need a ref_entry to pass to
      report_refname_conflict(), it is sufficient to store the refname of
      the conflicting reference.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      521331cc
    • M
      report_refname_conflict(): inline function · 385e8af5
      Michael Haggerty 提交于
      It wasn't pulling its weight. And we are about to need code similar to
      this where no ref_entry is available and with more diverse error
      messages. Rather than try to generalize the function, just inline it.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      385e8af5
    • M
      entry_matches(): inline function · 8bfac19a
      Michael Haggerty 提交于
      It wasn't pulling its weight. And in a moment we will need similar
      tests that take a refname rather than a ref_entry as parameter, which
      would have made entry_matches() even less useful.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      8bfac19a
    • M
      is_refname_available(): convert local variable "dirname" to strbuf · 6075f307
      Michael Haggerty 提交于
      This change wouldn't be worth it by itself, but in a moment we will
      use the strbuf for more string juggling.
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      6075f307
    • M
      is_refname_available(): avoid shadowing "dir" variable · 9ef6eaa2
      Michael Haggerty 提交于
      The function had a "dir" parameter that was shadowed by a local "dir"
      variable within a code block. Use the former in place of the latter.
      (This is consistent with "dir"'s use elsewhere in the function.)
      Signed-off-by: NMichael Haggerty <mhagger@alum.mit.edu>
      9ef6eaa2