Re: [PATCH v6 40/42] refs.c: pass a skip list to name_conflict_fn
Fixed. Thanks. On Thu, May 1, 2014 at 9:22 PM, Eric Sunshine sunsh...@sunshineco.com wrote: On Thu, May 1, 2014 at 4:37 PM, Ronnie Sahlberg sahlb...@google.com wrote: Allow passing a list of refs to ckip checking to name_conflict_fn. s/ckip/skip/ There are some conditions where we want to allow a temporary conflict and skip checking those refs. For example if we have a transaction that 1, guarantees that m is a packed refs and there is no loose ref for m 2, the transaction will delete m from the packed ref 3, the transaction will create conflicting m/m For this case we want to be able to lock anc create m/m since we know that the s/anc/and/ conflict is only transient. I.e. the conflict will be automatically resolved by the transaction when it deletes m. Signed-off-by: Ronnie Sahlberg sahlb...@google.com --- refs.c | 43 +-- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/refs.c b/refs.c index b525076..eb75927 100644 --- a/refs.c +++ b/refs.c @@ -789,11 +789,19 @@ struct name_conflict_cb { const char *refname; const char *oldrefname; const char *conflicting_refname; + const char **skip; + int skipnum; }; static int name_conflict_fn(struct ref_entry *entry, void *cb_data) { struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data; + int i; + for(i = 0; i data-skipnum; i++) { + if (!strcmp(entry-name, data-skip[i])) { + return 0; + } + } if (data-oldrefname !strcmp(data-oldrefname, entry-name)) return 0; if (names_conflict(data-refname, entry-name)) { @@ -808,15 +816,21 @@ static int name_conflict_fn(struct ref_entry *entry, void *cb_data) * conflicting with the name of an existing reference in dir. If * oldrefname is non-NULL, ignore potential conflicts with oldrefname * (e.g., because oldrefname is scheduled for deletion in the same - * operation). + * operation). skip contains a list of refs we want to skip checking for + * conflicts with. Refs may be skipped due to us knowing that it will + * be deleted later during a transaction that deletes one reference and then + * creates a new conflicting reference. For example a rename from m to m/m. */ static int is_refname_available(const char *refname, const char *oldrefname, - struct ref_dir *dir) + struct ref_dir *dir, + const char **skip, int skipnum) { struct name_conflict_cb data; data.refname = refname; data.oldrefname = oldrefname; data.conflicting_refname = NULL; + data.skip = skip; + data.skipnum = skipnum; sort_ref_dir(dir); if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, data)) { @@ -2032,7 +2046,8 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) static struct ref_lock *lock_ref_sha1_basic(const char *refname, const unsigned char *old_sha1, - int flags, int *type_p) + int flags, int *type_p, + const char **skip, int skipnum) { char *ref_file; const char *orig_refname = refname; @@ -2079,7 +2094,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, * name is a proper prefix of our refname. */ if (missing -!is_refname_available(refname, NULL, get_packed_refs(ref_cache))) { +!is_refname_available(refname, NULL, + get_packed_refs(ref_cache), + skip, skipnum)) { last_errno = ENOTDIR; goto error_return; } @@ -2137,7 +2154,7 @@ struct ref_lock *lock_any_ref_for_update(const char *refname, const unsigned char *old_sha1, int flags, int *type_p) { - return lock_ref_sha1_basic(refname, old_sha1, flags, type_p); + return lock_ref_sha1_basic(refname, old_sha1, flags, type_p, NULL, 0); } /* @@ -2576,6 +2593,9 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms int log = !lstat(git_path(logs/%s, oldrefname), loginfo); const char *symref = NULL; + if (!strcmp(oldrefname, newrefname)) + return 0; + if (log S_ISLNK(loginfo.st_mode)) return error(reflog for %s is a symlink, oldrefname); @@ -2586,10 +2606,12 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms if (!symref) return error(refname %s not found, oldrefname); - if
[PATCH v6 40/42] refs.c: pass a skip list to name_conflict_fn
Allow passing a list of refs to ckip checking to name_conflict_fn. There are some conditions where we want to allow a temporary conflict and skip checking those refs. For example if we have a transaction that 1, guarantees that m is a packed refs and there is no loose ref for m 2, the transaction will delete m from the packed ref 3, the transaction will create conflicting m/m For this case we want to be able to lock anc create m/m since we know that the conflict is only transient. I.e. the conflict will be automatically resolved by the transaction when it deletes m. Signed-off-by: Ronnie Sahlberg sahlb...@google.com --- refs.c | 43 +-- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/refs.c b/refs.c index b525076..eb75927 100644 --- a/refs.c +++ b/refs.c @@ -789,11 +789,19 @@ struct name_conflict_cb { const char *refname; const char *oldrefname; const char *conflicting_refname; + const char **skip; + int skipnum; }; static int name_conflict_fn(struct ref_entry *entry, void *cb_data) { struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data; + int i; + for(i = 0; i data-skipnum; i++) { + if (!strcmp(entry-name, data-skip[i])) { + return 0; + } + } if (data-oldrefname !strcmp(data-oldrefname, entry-name)) return 0; if (names_conflict(data-refname, entry-name)) { @@ -808,15 +816,21 @@ static int name_conflict_fn(struct ref_entry *entry, void *cb_data) * conflicting with the name of an existing reference in dir. If * oldrefname is non-NULL, ignore potential conflicts with oldrefname * (e.g., because oldrefname is scheduled for deletion in the same - * operation). + * operation). skip contains a list of refs we want to skip checking for + * conflicts with. Refs may be skipped due to us knowing that it will + * be deleted later during a transaction that deletes one reference and then + * creates a new conflicting reference. For example a rename from m to m/m. */ static int is_refname_available(const char *refname, const char *oldrefname, - struct ref_dir *dir) + struct ref_dir *dir, + const char **skip, int skipnum) { struct name_conflict_cb data; data.refname = refname; data.oldrefname = oldrefname; data.conflicting_refname = NULL; + data.skip = skip; + data.skipnum = skipnum; sort_ref_dir(dir); if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, data)) { @@ -2032,7 +2046,8 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) static struct ref_lock *lock_ref_sha1_basic(const char *refname, const unsigned char *old_sha1, - int flags, int *type_p) + int flags, int *type_p, + const char **skip, int skipnum) { char *ref_file; const char *orig_refname = refname; @@ -2079,7 +2094,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, * name is a proper prefix of our refname. */ if (missing -!is_refname_available(refname, NULL, get_packed_refs(ref_cache))) { +!is_refname_available(refname, NULL, + get_packed_refs(ref_cache), + skip, skipnum)) { last_errno = ENOTDIR; goto error_return; } @@ -2137,7 +2154,7 @@ struct ref_lock *lock_any_ref_for_update(const char *refname, const unsigned char *old_sha1, int flags, int *type_p) { - return lock_ref_sha1_basic(refname, old_sha1, flags, type_p); + return lock_ref_sha1_basic(refname, old_sha1, flags, type_p, NULL, 0); } /* @@ -2576,6 +2593,9 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms int log = !lstat(git_path(logs/%s, oldrefname), loginfo); const char *symref = NULL; + if (!strcmp(oldrefname, newrefname)) + return 0; + if (log S_ISLNK(loginfo.st_mode)) return error(reflog for %s is a symlink, oldrefname); @@ -2586,10 +2606,12 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms if (!symref) return error(refname %s not found, oldrefname); - if (!is_refname_available(newrefname, oldrefname, get_packed_refs(ref_cache))) + if (!is_refname_available(newrefname, oldrefname, + get_packed_refs(ref_cache), NULL, 0)) return 1; - if (!is_refname_available(newrefname, oldrefname,
Re: [PATCH v6 40/42] refs.c: pass a skip list to name_conflict_fn
On Thu, May 1, 2014 at 4:37 PM, Ronnie Sahlberg sahlb...@google.com wrote: Allow passing a list of refs to ckip checking to name_conflict_fn. s/ckip/skip/ There are some conditions where we want to allow a temporary conflict and skip checking those refs. For example if we have a transaction that 1, guarantees that m is a packed refs and there is no loose ref for m 2, the transaction will delete m from the packed ref 3, the transaction will create conflicting m/m For this case we want to be able to lock anc create m/m since we know that the s/anc/and/ conflict is only transient. I.e. the conflict will be automatically resolved by the transaction when it deletes m. Signed-off-by: Ronnie Sahlberg sahlb...@google.com --- refs.c | 43 +-- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/refs.c b/refs.c index b525076..eb75927 100644 --- a/refs.c +++ b/refs.c @@ -789,11 +789,19 @@ struct name_conflict_cb { const char *refname; const char *oldrefname; const char *conflicting_refname; + const char **skip; + int skipnum; }; static int name_conflict_fn(struct ref_entry *entry, void *cb_data) { struct name_conflict_cb *data = (struct name_conflict_cb *)cb_data; + int i; + for(i = 0; i data-skipnum; i++) { + if (!strcmp(entry-name, data-skip[i])) { + return 0; + } + } if (data-oldrefname !strcmp(data-oldrefname, entry-name)) return 0; if (names_conflict(data-refname, entry-name)) { @@ -808,15 +816,21 @@ static int name_conflict_fn(struct ref_entry *entry, void *cb_data) * conflicting with the name of an existing reference in dir. If * oldrefname is non-NULL, ignore potential conflicts with oldrefname * (e.g., because oldrefname is scheduled for deletion in the same - * operation). + * operation). skip contains a list of refs we want to skip checking for + * conflicts with. Refs may be skipped due to us knowing that it will + * be deleted later during a transaction that deletes one reference and then + * creates a new conflicting reference. For example a rename from m to m/m. */ static int is_refname_available(const char *refname, const char *oldrefname, - struct ref_dir *dir) + struct ref_dir *dir, + const char **skip, int skipnum) { struct name_conflict_cb data; data.refname = refname; data.oldrefname = oldrefname; data.conflicting_refname = NULL; + data.skip = skip; + data.skipnum = skipnum; sort_ref_dir(dir); if (do_for_each_entry_in_dir(dir, 0, name_conflict_fn, data)) { @@ -2032,7 +2046,8 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log) static struct ref_lock *lock_ref_sha1_basic(const char *refname, const unsigned char *old_sha1, - int flags, int *type_p) + int flags, int *type_p, + const char **skip, int skipnum) { char *ref_file; const char *orig_refname = refname; @@ -2079,7 +2094,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, * name is a proper prefix of our refname. */ if (missing -!is_refname_available(refname, NULL, get_packed_refs(ref_cache))) { +!is_refname_available(refname, NULL, + get_packed_refs(ref_cache), + skip, skipnum)) { last_errno = ENOTDIR; goto error_return; } @@ -2137,7 +2154,7 @@ struct ref_lock *lock_any_ref_for_update(const char *refname, const unsigned char *old_sha1, int flags, int *type_p) { - return lock_ref_sha1_basic(refname, old_sha1, flags, type_p); + return lock_ref_sha1_basic(refname, old_sha1, flags, type_p, NULL, 0); } /* @@ -2576,6 +2593,9 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms int log = !lstat(git_path(logs/%s, oldrefname), loginfo); const char *symref = NULL; + if (!strcmp(oldrefname, newrefname)) + return 0; + if (log S_ISLNK(loginfo.st_mode)) return error(reflog for %s is a symlink, oldrefname); @@ -2586,10 +2606,12 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms if (!symref) return error(refname %s not found, oldrefname); - if (!is_refname_available(newrefname, oldrefname, get_packed_refs(ref_cache))) + if