Skip to content

Commit 711a11c

Browse files
committed
Merge branch 'mh/packed-ref-store-prep'
The implementation of "ref" API around the "packed refs" have been cleaned up, in preparation for further changes. * mh/packed-ref-store-prep: (25 commits) cache_ref_iterator_begin(): avoid priming unneeded directories ref-filter: limit traversal to prefix create_ref_entry(): remove `check_name` option refs_ref_iterator_begin(): handle `GIT_REF_PARANOIA` read_packed_refs(): report unexpected fopen() failures read_packed_refs(): do more of the work of reading packed refs get_packed_ref_cache(): assume "packed-refs" won't change while locked should_pack_ref(): new function, extracted from `files_pack_refs()` ref_update_reject_duplicates(): add a sanity check ref_update_reject_duplicates(): use `size_t` rather than `int` ref_update_reject_duplicates(): expose function to whole refs module ref_transaction_prepare(): new optional step for reference updates ref_transaction_commit(): check for valid `transaction->state` files_transaction_cleanup(): new helper function files_ref_store: put the packed files lock directly in this struct files-backend: move `lock` member to `files_ref_store` lockfile: add a new method, is_lock_file_locked() ref_store: take a `msg` parameter when deleting references refs: use `size_t` indexes when iterating over ref transaction updates refs_ref_iterator_begin(): don't check prefixes redundantly ...
2 parents 53083f8 + f23092f commit 711a11c

15 files changed

+659
-203
lines changed

builtin/fetch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
941941
for (ref = stale_refs; ref; ref = ref->next)
942942
string_list_append(&refnames, ref->name);
943943

944-
result = delete_refs(&refnames, 0);
944+
result = delete_refs("fetch: prune", &refnames, 0);
945945
string_list_clear(&refnames, 0);
946946
}
947947

builtin/remote.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ static int rm(int argc, const char **argv)
786786
strbuf_release(&buf);
787787

788788
if (!result)
789-
result = delete_refs(&branches, REF_NODEREF);
789+
result = delete_refs("remote: remove", &branches, REF_NODEREF);
790790
string_list_clear(&branches, 0);
791791

792792
if (skipped.nr) {
@@ -1304,7 +1304,7 @@ static int prune_remote(const char *remote, int dry_run)
13041304
string_list_sort(&refs_to_prune);
13051305

13061306
if (!dry_run)
1307-
result |= delete_refs(&refs_to_prune, 0);
1307+
result |= delete_refs("remote: prune", &refs_to_prune, 0);
13081308

13091309
for_each_string_list_item(item, &states.stale) {
13101310
const char *refname = item->util;

lockfile.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,14 @@ static inline int hold_lock_file_for_update(
175175
return hold_lock_file_for_update_timeout(lk, path, flags, 0);
176176
}
177177

178+
/*
179+
* Return a nonzero value iff `lk` is currently locked.
180+
*/
181+
static inline int is_lock_file_locked(struct lock_file *lk)
182+
{
183+
return is_tempfile_active(&lk->tempfile);
184+
}
185+
178186
/*
179187
* Append an appropriate error message to `buf` following the failure
180188
* of `hold_lock_file_for_update()` to lock `path`. `err` should be the

ref-filter.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,68 @@ static int filter_pattern_match(struct ref_filter *filter, const char *refname)
16711671
return match_pattern(filter, refname);
16721672
}
16731673

1674+
/*
1675+
* Find the longest prefix of pattern we can pass to
1676+
* `for_each_fullref_in()`, namely the part of pattern preceding the
1677+
* first glob character. (Note that `for_each_fullref_in()` is
1678+
* perfectly happy working with a prefix that doesn't end at a
1679+
* pathname component boundary.)
1680+
*/
1681+
static void find_longest_prefix(struct strbuf *out, const char *pattern)
1682+
{
1683+
const char *p;
1684+
1685+
for (p = pattern; *p && !is_glob_special(*p); p++)
1686+
;
1687+
1688+
strbuf_add(out, pattern, p - pattern);
1689+
}
1690+
1691+
/*
1692+
* This is the same as for_each_fullref_in(), but it tries to iterate
1693+
* only over the patterns we'll care about. Note that it _doesn't_ do a full
1694+
* pattern match, so the callback still has to match each ref individually.
1695+
*/
1696+
static int for_each_fullref_in_pattern(struct ref_filter *filter,
1697+
each_ref_fn cb,
1698+
void *cb_data,
1699+
int broken)
1700+
{
1701+
struct strbuf prefix = STRBUF_INIT;
1702+
int ret;
1703+
1704+
if (!filter->match_as_path) {
1705+
/*
1706+
* in this case, the patterns are applied after
1707+
* prefixes like "refs/heads/" etc. are stripped off,
1708+
* so we have to look at everything:
1709+
*/
1710+
return for_each_fullref_in("", cb, cb_data, broken);
1711+
}
1712+
1713+
if (!filter->name_patterns[0]) {
1714+
/* no patterns; we have to look at everything */
1715+
return for_each_fullref_in("", cb, cb_data, broken);
1716+
}
1717+
1718+
if (filter->name_patterns[1]) {
1719+
/*
1720+
* multiple patterns; in theory this could still work as long
1721+
* as the patterns are disjoint. We'd just make multiple calls
1722+
* to for_each_ref(). But if they're not disjoint, we'd end up
1723+
* reporting the same ref multiple times. So let's punt on that
1724+
* for now.
1725+
*/
1726+
return for_each_fullref_in("", cb, cb_data, broken);
1727+
}
1728+
1729+
find_longest_prefix(&prefix, filter->name_patterns[0]);
1730+
1731+
ret = for_each_fullref_in(prefix.buf, cb, cb_data, broken);
1732+
strbuf_release(&prefix);
1733+
return ret;
1734+
}
1735+
16741736
/*
16751737
* Given a ref (sha1, refname), check if the ref belongs to the array
16761738
* of sha1s. If the given ref is a tag, check if the given tag points
@@ -1917,7 +1979,7 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int
19171979
else if (filter->kind == FILTER_REFS_TAGS)
19181980
ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata, broken);
19191981
else if (filter->kind & FILTER_REFS_ALL)
1920-
ret = for_each_fullref_in("", ref_filter_handler, &ref_cbdata, broken);
1982+
ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata, broken);
19211983
if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD))
19221984
head_ref(ref_filter_handler, &ref_cbdata);
19231985
}

refs.c

Lines changed: 125 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -848,11 +848,24 @@ struct ref_transaction *ref_transaction_begin(struct strbuf *err)
848848

849849
void ref_transaction_free(struct ref_transaction *transaction)
850850
{
851-
int i;
851+
size_t i;
852852

853853
if (!transaction)
854854
return;
855855

856+
switch (transaction->state) {
857+
case REF_TRANSACTION_OPEN:
858+
case REF_TRANSACTION_CLOSED:
859+
/* OK */
860+
break;
861+
case REF_TRANSACTION_PREPARED:
862+
die("BUG: free called on a prepared reference transaction");
863+
break;
864+
default:
865+
die("BUG: unexpected reference transaction state");
866+
break;
867+
}
868+
856869
for (i = 0; i < transaction->nr; i++) {
857870
free(transaction->updates[i]->msg);
858871
free(transaction->updates[i]);
@@ -1246,8 +1259,19 @@ struct ref_iterator *refs_ref_iterator_begin(
12461259
{
12471260
struct ref_iterator *iter;
12481261

1262+
if (ref_paranoia < 0)
1263+
ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
1264+
if (ref_paranoia)
1265+
flags |= DO_FOR_EACH_INCLUDE_BROKEN;
1266+
12491267
iter = refs->be->iterator_begin(refs, prefix, flags);
1250-
iter = prefix_ref_iterator_begin(iter, prefix, trim);
1268+
1269+
/*
1270+
* `iterator_begin()` already takes care of prefix, but we
1271+
* might need to do some trimming:
1272+
*/
1273+
if (trim)
1274+
iter = prefix_ref_iterator_begin(iter, "", trim);
12511275

12521276
return iter;
12531277
}
@@ -1683,18 +1707,108 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
16831707
refs_heads_master, logmsg);
16841708
}
16851709

1686-
int ref_transaction_commit(struct ref_transaction *transaction,
1687-
struct strbuf *err)
1710+
int ref_update_reject_duplicates(struct string_list *refnames,
1711+
struct strbuf *err)
1712+
{
1713+
size_t i, n = refnames->nr;
1714+
1715+
assert(err);
1716+
1717+
for (i = 1; i < n; i++) {
1718+
int cmp = strcmp(refnames->items[i - 1].string,
1719+
refnames->items[i].string);
1720+
1721+
if (!cmp) {
1722+
strbuf_addf(err,
1723+
"multiple updates for ref '%s' not allowed.",
1724+
refnames->items[i].string);
1725+
return 1;
1726+
} else if (cmp > 0) {
1727+
die("BUG: ref_update_reject_duplicates() received unsorted list");
1728+
}
1729+
}
1730+
return 0;
1731+
}
1732+
1733+
int ref_transaction_prepare(struct ref_transaction *transaction,
1734+
struct strbuf *err)
16881735
{
16891736
struct ref_store *refs = transaction->ref_store;
16901737

1738+
switch (transaction->state) {
1739+
case REF_TRANSACTION_OPEN:
1740+
/* Good. */
1741+
break;
1742+
case REF_TRANSACTION_PREPARED:
1743+
die("BUG: prepare called twice on reference transaction");
1744+
break;
1745+
case REF_TRANSACTION_CLOSED:
1746+
die("BUG: prepare called on a closed reference transaction");
1747+
break;
1748+
default:
1749+
die("BUG: unexpected reference transaction state");
1750+
break;
1751+
}
1752+
16911753
if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
16921754
strbuf_addstr(err,
16931755
_("ref updates forbidden inside quarantine environment"));
16941756
return -1;
16951757
}
16961758

1697-
return refs->be->transaction_commit(refs, transaction, err);
1759+
return refs->be->transaction_prepare(refs, transaction, err);
1760+
}
1761+
1762+
int ref_transaction_abort(struct ref_transaction *transaction,
1763+
struct strbuf *err)
1764+
{
1765+
struct ref_store *refs = transaction->ref_store;
1766+
int ret = 0;
1767+
1768+
switch (transaction->state) {
1769+
case REF_TRANSACTION_OPEN:
1770+
/* No need to abort explicitly. */
1771+
break;
1772+
case REF_TRANSACTION_PREPARED:
1773+
ret = refs->be->transaction_abort(refs, transaction, err);
1774+
break;
1775+
case REF_TRANSACTION_CLOSED:
1776+
die("BUG: abort called on a closed reference transaction");
1777+
break;
1778+
default:
1779+
die("BUG: unexpected reference transaction state");
1780+
break;
1781+
}
1782+
1783+
ref_transaction_free(transaction);
1784+
return ret;
1785+
}
1786+
1787+
int ref_transaction_commit(struct ref_transaction *transaction,
1788+
struct strbuf *err)
1789+
{
1790+
struct ref_store *refs = transaction->ref_store;
1791+
int ret;
1792+
1793+
switch (transaction->state) {
1794+
case REF_TRANSACTION_OPEN:
1795+
/* Need to prepare first. */
1796+
ret = ref_transaction_prepare(transaction, err);
1797+
if (ret)
1798+
return ret;
1799+
break;
1800+
case REF_TRANSACTION_PREPARED:
1801+
/* Fall through to finish. */
1802+
break;
1803+
case REF_TRANSACTION_CLOSED:
1804+
die("BUG: commit called on a closed reference transaction");
1805+
break;
1806+
default:
1807+
die("BUG: unexpected reference transaction state");
1808+
break;
1809+
}
1810+
1811+
return refs->be->transaction_finish(refs, transaction, err);
16981812
}
16991813

17001814
int refs_verify_refname_available(struct ref_store *refs,
@@ -1896,15 +2010,16 @@ int initial_ref_transaction_commit(struct ref_transaction *transaction,
18962010
return refs->be->initial_transaction_commit(refs, transaction, err);
18972011
}
18982012

1899-
int refs_delete_refs(struct ref_store *refs, struct string_list *refnames,
1900-
unsigned int flags)
2013+
int refs_delete_refs(struct ref_store *refs, const char *msg,
2014+
struct string_list *refnames, unsigned int flags)
19012015
{
1902-
return refs->be->delete_refs(refs, refnames, flags);
2016+
return refs->be->delete_refs(refs, msg, refnames, flags);
19032017
}
19042018

1905-
int delete_refs(struct string_list *refnames, unsigned int flags)
2019+
int delete_refs(const char *msg, struct string_list *refnames,
2020+
unsigned int flags)
19062021
{
1907-
return refs_delete_refs(get_main_ref_store(), refnames, flags);
2022+
return refs_delete_refs(get_main_ref_store(), msg, refnames, flags);
19082023
}
19092024

19102025
int refs_rename_ref(struct ref_store *refs, const char *oldref,

0 commit comments

Comments
 (0)