Re: [PATCH v20 33/48] walker.c: use ref transaction for ref updates

2014-07-14 Thread Ronnie Sahlberg
On Tue, Jul 8, 2014 at 6:33 AM, Michael Haggerty  wrote:
> On 06/20/2014 04:43 PM, Ronnie Sahlberg wrote:
>> Switch to using ref transactions in walker_fetch(). As part of the 
>> refactoring
>> to use ref transactions we also fix a potential memory leak where in the
>> original code if write_ref_sha1() would fail we would end up returning from
>> the function without free()ing the msg string.
>>
>> Note that this function is only called when fetching from a remote HTTP
>> repository onto the local (most of the time single-user) repository which
>> likely means that the type of collissions that the previous locking would
>
> s/collissions/collisions/
>
>> protect against and cause the fetch to fail for to be even more rare.
>
> Grammatico: s/to be/are/ ?

Thanks.  Fixed.

>
>> Reviewed-by: Jonathan Nieder 
>> Signed-off-by: Ronnie Sahlberg 
>> ---
>>  walker.c | 59 +++
>>  1 file changed, 35 insertions(+), 24 deletions(-)
>>
>> diff --git a/walker.c b/walker.c
>> index 1dd86b8..60d9f9e 100644
>> --- a/walker.c
>> +++ b/walker.c
>> @@ -251,39 +251,36 @@ void walker_targets_free(int targets, char **target, 
>> const char **write_ref)
>>  int walker_fetch(struct walker *walker, int targets, char **target,
>>const char **write_ref, const char *write_ref_log_details)
>>  {
>> - struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
>> + struct strbuf ref_name = STRBUF_INIT;
>> + struct strbuf err = STRBUF_INIT;
>> + struct ref_transaction *transaction = NULL;
>>   unsigned char *sha1 = xmalloc(targets * 20);
>> - char *msg;
>> - int ret;
>> + char *msg = NULL;
>>   int i;
>>
>>   save_commit_buffer = 0;
>>
>> - for (i = 0; i < targets; i++) {
>> - if (!write_ref || !write_ref[i])
>> - continue;
>> -
>> - lock[i] = lock_ref_sha1(write_ref[i], NULL);
>> - if (!lock[i]) {
>> - error("Can't lock ref %s", write_ref[i]);
>> - goto unlock_and_fail;
>> + if (write_ref) {
>> + transaction = ref_transaction_begin(&err);
>> + if (!transaction) {
>> + error("%s", err.buf);
>> + goto rollback_and_fail;
>>   }
>>   }
>> -
>
> Is there some reason why the transaction cannot be built up during a
> single iteration over targets, thereby also avoiding the need for the
> sha1[20*i] stuff?  This seems like exactly the kind of situation where
> transactions should *save* code.  But perhaps I've overlooked a
> dependency between the two loops.

I did it this way to keep the changes minimal. But you are right that
with this we can do a larger refactoring and start saving some code.
I can add changes to a later series to do that change but I want to
keep this change as small as possible for now.

regards
ronnie sahlberg
--
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 v20 33/48] walker.c: use ref transaction for ref updates

2014-07-08 Thread Michael Haggerty
On 06/20/2014 04:43 PM, Ronnie Sahlberg wrote:
> Switch to using ref transactions in walker_fetch(). As part of the refactoring
> to use ref transactions we also fix a potential memory leak where in the
> original code if write_ref_sha1() would fail we would end up returning from
> the function without free()ing the msg string.
> 
> Note that this function is only called when fetching from a remote HTTP
> repository onto the local (most of the time single-user) repository which
> likely means that the type of collissions that the previous locking would

s/collissions/collisions/

> protect against and cause the fetch to fail for to be even more rare.

Grammatico: s/to be/are/ ?

> Reviewed-by: Jonathan Nieder 
> Signed-off-by: Ronnie Sahlberg 
> ---
>  walker.c | 59 +++
>  1 file changed, 35 insertions(+), 24 deletions(-)
> 
> diff --git a/walker.c b/walker.c
> index 1dd86b8..60d9f9e 100644
> --- a/walker.c
> +++ b/walker.c
> @@ -251,39 +251,36 @@ void walker_targets_free(int targets, char **target, 
> const char **write_ref)
>  int walker_fetch(struct walker *walker, int targets, char **target,
>const char **write_ref, const char *write_ref_log_details)
>  {
> - struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
> + struct strbuf ref_name = STRBUF_INIT;
> + struct strbuf err = STRBUF_INIT;
> + struct ref_transaction *transaction = NULL;
>   unsigned char *sha1 = xmalloc(targets * 20);
> - char *msg;
> - int ret;
> + char *msg = NULL;
>   int i;
>  
>   save_commit_buffer = 0;
>  
> - for (i = 0; i < targets; i++) {
> - if (!write_ref || !write_ref[i])
> - continue;
> -
> - lock[i] = lock_ref_sha1(write_ref[i], NULL);
> - if (!lock[i]) {
> - error("Can't lock ref %s", write_ref[i]);
> - goto unlock_and_fail;
> + if (write_ref) {
> + transaction = ref_transaction_begin(&err);
> + if (!transaction) {
> + error("%s", err.buf);
> + goto rollback_and_fail;
>   }
>   }
> -

Is there some reason why the transaction cannot be built up during a
single iteration over targets, thereby also avoiding the need for the
sha1[20*i] stuff?  This seems like exactly the kind of situation where
transactions should *save* code.  But perhaps I've overlooked a
dependency between the two loops.

>   if (!walker->get_recover)
>   for_each_ref(mark_complete, NULL);
>  
>   for (i = 0; i < targets; i++) {
>   if (interpret_target(walker, target[i], &sha1[20 * i])) {
>   error("Could not interpret response from server '%s' as 
> something to pull", target[i]);
> - goto unlock_and_fail;
> + goto rollback_and_fail;
>   }
>   if (process(walker, lookup_unknown_object(&sha1[20 * i])))
> - goto unlock_and_fail;
> + goto rollback_and_fail;
>   }
>  
>   if (loop(walker))
> - goto unlock_and_fail;
> + goto rollback_and_fail;
>  
>   if (write_ref_log_details) {
>   msg = xmalloc(strlen(write_ref_log_details) + 12);
> @@ -294,19 +291,33 @@ int walker_fetch(struct walker *walker, int targets, 
> char **target,
>   for (i = 0; i < targets; i++) {
>   if (!write_ref || !write_ref[i])
>   continue;
> - ret = write_ref_sha1(lock[i], &sha1[20 * i], msg ? msg : "fetch 
> (unknown)");
> - lock[i] = NULL;
> - if (ret)
> - goto unlock_and_fail;
> + strbuf_reset(&ref_name);
> + strbuf_addf(&ref_name, "refs/%s", write_ref[i]);
> + if (ref_transaction_update(transaction, ref_name.buf,
> +&sha1[20 * i], NULL, 0, 0,
> +&err)) {
> + error("%s", err.buf);
> + goto rollback_and_fail;
> + }
> + }
> + if (write_ref) {
> + if (ref_transaction_commit(transaction,
> +msg ? msg : "fetch (unknown)",
> +&err)) {
> + error("%s", err.buf);
> + goto rollback_and_fail;
> + }
> + ref_transaction_free(transaction);
>   }
> - free(msg);
>  
> + free(msg);
>   return 0;
>  
> -unlock_and_fail:
> - for (i = 0; i < targets; i++)
> - if (lock[i])
> - unlock_ref(lock[i]);
> +rollback_and_fail:
> + ref_transaction_free(transaction);
> + free(msg);
> + strbuf_release(&err);
> + strbuf_release(&ref_name);
>  
>   return -1;
>  }
> 

Michael

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

--

[PATCH v20 33/48] walker.c: use ref transaction for ref updates

2014-06-20 Thread Ronnie Sahlberg
Switch to using ref transactions in walker_fetch(). As part of the refactoring
to use ref transactions we also fix a potential memory leak where in the
original code if write_ref_sha1() would fail we would end up returning from
the function without free()ing the msg string.

Note that this function is only called when fetching from a remote HTTP
repository onto the local (most of the time single-user) repository which
likely means that the type of collissions that the previous locking would
protect against and cause the fetch to fail for to be even more rare.

Reviewed-by: Jonathan Nieder 
Signed-off-by: Ronnie Sahlberg 
---
 walker.c | 59 +++
 1 file changed, 35 insertions(+), 24 deletions(-)

diff --git a/walker.c b/walker.c
index 1dd86b8..60d9f9e 100644
--- a/walker.c
+++ b/walker.c
@@ -251,39 +251,36 @@ void walker_targets_free(int targets, char **target, 
const char **write_ref)
 int walker_fetch(struct walker *walker, int targets, char **target,
 const char **write_ref, const char *write_ref_log_details)
 {
-   struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
+   struct strbuf ref_name = STRBUF_INIT;
+   struct strbuf err = STRBUF_INIT;
+   struct ref_transaction *transaction = NULL;
unsigned char *sha1 = xmalloc(targets * 20);
-   char *msg;
-   int ret;
+   char *msg = NULL;
int i;
 
save_commit_buffer = 0;
 
-   for (i = 0; i < targets; i++) {
-   if (!write_ref || !write_ref[i])
-   continue;
-
-   lock[i] = lock_ref_sha1(write_ref[i], NULL);
-   if (!lock[i]) {
-   error("Can't lock ref %s", write_ref[i]);
-   goto unlock_and_fail;
+   if (write_ref) {
+   transaction = ref_transaction_begin(&err);
+   if (!transaction) {
+   error("%s", err.buf);
+   goto rollback_and_fail;
}
}
-
if (!walker->get_recover)
for_each_ref(mark_complete, NULL);
 
for (i = 0; i < targets; i++) {
if (interpret_target(walker, target[i], &sha1[20 * i])) {
error("Could not interpret response from server '%s' as 
something to pull", target[i]);
-   goto unlock_and_fail;
+   goto rollback_and_fail;
}
if (process(walker, lookup_unknown_object(&sha1[20 * i])))
-   goto unlock_and_fail;
+   goto rollback_and_fail;
}
 
if (loop(walker))
-   goto unlock_and_fail;
+   goto rollback_and_fail;
 
if (write_ref_log_details) {
msg = xmalloc(strlen(write_ref_log_details) + 12);
@@ -294,19 +291,33 @@ int walker_fetch(struct walker *walker, int targets, char 
**target,
for (i = 0; i < targets; i++) {
if (!write_ref || !write_ref[i])
continue;
-   ret = write_ref_sha1(lock[i], &sha1[20 * i], msg ? msg : "fetch 
(unknown)");
-   lock[i] = NULL;
-   if (ret)
-   goto unlock_and_fail;
+   strbuf_reset(&ref_name);
+   strbuf_addf(&ref_name, "refs/%s", write_ref[i]);
+   if (ref_transaction_update(transaction, ref_name.buf,
+  &sha1[20 * i], NULL, 0, 0,
+  &err)) {
+   error("%s", err.buf);
+   goto rollback_and_fail;
+   }
+   }
+   if (write_ref) {
+   if (ref_transaction_commit(transaction,
+  msg ? msg : "fetch (unknown)",
+  &err)) {
+   error("%s", err.buf);
+   goto rollback_and_fail;
+   }
+   ref_transaction_free(transaction);
}
-   free(msg);
 
+   free(msg);
return 0;
 
-unlock_and_fail:
-   for (i = 0; i < targets; i++)
-   if (lock[i])
-   unlock_ref(lock[i]);
+rollback_and_fail:
+   ref_transaction_free(transaction);
+   free(msg);
+   strbuf_release(&err);
+   strbuf_release(&ref_name);
 
return -1;
 }
-- 
2.0.0.420.g181e020.dirty

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