{"thread":{"id":"3628","subject":"[PATCH 4/6] http-push: improve remote lock management","startedAt":"2006-03-11T04:18:12Z","lastAt":"2006-03-11T04:18:12Z","messageCount":1,"participants":["Nick Hengeveld"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"17449","messageId":"20060311041812.GF3997@reactrix.com","threadId":"3628","inReplyTo":null,"subject":"[PATCH 4/6] http-push: improve remote lock management","fromName":"Nick Hengeveld","fromEmail":"nickh@reactrix.com","sentAt":"2006-03-11T04:18:12Z","receivedAt":"2006-03-11T04:18:12Z","isPatch":true,"sender":{"key":"nickh@reactrix.com","avatar":null},"body":"Associate the remote locks with the remote repo, add a function to check\nand refresh all current locks.\n\n---\n\n http-push.c |  149 ++++++++++++++++++++++++++++++-----------------------------\n 1 files changed, 76 insertions(+), 73 deletions(-)\n\nfd1de0bf29e5e0fa63b851cb2195fbe05ebf80c2\ndiff --git a/http-push.c b/http-push.c\nindex 755bcb8..ece40da 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -80,10 +80,10 @@ struct repo\n \tchar *url;\n \tint path_len;\n \tstruct packed_git *packs;\n+\tstruct remote_lock *locks;\n };\n \n static struct repo *remote = NULL;\n-static struct remote_lock *remote_locks = NULL;\n \n enum transfer_state {\n \tNEED_PUSH,\n@@ -135,7 +135,6 @@ struct remote_lock\n \tchar *token;\n \ttime_t start_time;\n \tlong timeout;\n-\tint active;\n \tint refreshing;\n \tstruct remote_lock *next;\n };\n@@ -311,64 +310,69 @@ static void start_move(struct transfer_r\n \t}\n }\n \n-static int refresh_lock(struct remote_lock *check_lock)\n+static int refresh_lock(struct remote_lock *lock)\n {\n \tstruct active_request_slot *slot;\n \tstruct slot_results results;\n \tchar *if_header;\n \tchar timeout_header[25];\n \tstruct curl_slist *dav_headers = NULL;\n-\tstruct remote_lock *lock;\n-\tint time_remaining;\n-\ttime_t current_time;\n+\tint rc = 0;\n \n-\t/* Refresh all active locks if they're close to expiring */\n-\tfor (lock = remote_locks; lock; lock = lock->next) {\n-\t\tif (!lock->active)\n-\t\t\tcontinue;\n+\tlock->refreshing = 1;\n \n-\t\tcurrent_time = time(NULL);\n-\t\ttime_remaining = lock->start_time + lock->timeout\n-\t\t\t- current_time;\n-\t\tif (time_remaining > LOCK_REFRESH)\n-\t\t\tcontinue;\n+\tif_header = xmalloc(strlen(lock->token) + 25);\n+\tsprintf(if_header, \"If: (<opaquelocktoken:%s>)\", lock->token);\n+\tsprintf(timeout_header, \"Timeout: Second-%ld\", lock->timeout);\n+\tdav_headers = curl_slist_append(dav_headers, if_header);\n+\tdav_headers = curl_slist_append(dav_headers, timeout_header);\n \n-\t\tlock->refreshing = 1;\n+\tslot = get_active_slot();\n+\tslot->results = &results;\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);\n+\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\n \n-\t\tif_header = xmalloc(strlen(lock->token) + 25);\n-\t\tsprintf(if_header, \"If: (<opaquelocktoken:%s>)\", lock->token);\n-\t\tsprintf(timeout_header, \"Timeout: Second-%ld\", lock->timeout);\n-\t\tdav_headers = curl_slist_append(dav_headers, if_header);\n-\t\tdav_headers = curl_slist_append(dav_headers, timeout_header);\n+\tif (start_active_slot(slot)) {\n+\t\trun_active_slot(slot);\n+\t\tif (results.curl_result != CURLE_OK) {\n+\t\t\tfprintf(stderr, \"LOCK HTTP error %ld\\n\",\n+\t\t\t\tresults.http_code);\n+\t\t} else {\n+\t\t\tlock->start_time = time(NULL);\n+\t\t\trc = 1;\n+\t\t}\n+\t}\n \n-\t\tslot = get_active_slot();\n-\t\tslot->results = &results;\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_null);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_URL, lock->url);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, DAV_LOCK);\n-\t\tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\n+\tlock->refreshing = 0;\n+\tcurl_slist_free_all(dav_headers);\n+\tfree(if_header);\n \n-\t\tif (start_active_slot(slot)) {\n-\t\t\trun_active_slot(slot);\n-\t\t\tif (results.curl_result != CURLE_OK) {\n-\t\t\t\tfprintf(stderr, \"Got HTTP error %ld\\n\", results.http_code);\n-\t\t\t\tlock->active = 0;\n-\t\t\t} else {\n-\t\t\t\tlock->active = 1;\n-\t\t\t\tlock->start_time = time(NULL);\n+\treturn rc;\n+}\n+\n+static void check_locks()\n+{\n+\tstruct remote_lock *lock = remote->locks;\n+\ttime_t current_time = time(NULL);\n+\tint time_remaining;\n+\n+\twhile (lock) {\n+\t\ttime_remaining = lock->start_time + lock->timeout -\n+\t\t\tcurrent_time;\n+\t\tif (!lock->refreshing && time_remaining < LOCK_REFRESH) {\n+\t\t\tif (!refresh_lock(lock)) {\n+\t\t\t\tfprintf(stderr,\n+\t\t\t\t\t\"Unable to refresh lock for %s\\n\",\n+\t\t\t\t\tlock->url);\n+\t\t\t\taborted = 1;\n+\t\t\t\treturn;\n \t\t\t}\n \t\t}\n-\n-\t\tlock->refreshing = 0;\n-\t\tcurl_slist_free_all(dav_headers);\n-\t\tfree(if_header);\n+\t\tlock = lock->next;\n \t}\n-\n-\tif (check_lock)\n-\t\treturn check_lock->active;\n-\telse\n-\t\treturn 0;\n }\n \n static void release_request(struct transfer_request *request)\n@@ -396,7 +400,7 @@ static void finish_request(struct transf\n \trequest->slot = NULL;\n \n \t/* Keep locks active */\n-\trefresh_lock(request->lock);\n+\tcheck_locks();\n \n \tif (request->headers != NULL)\n \t\tcurl_slist_free_all(request->headers);\n@@ -483,6 +487,9 @@ static void add_request(struct object *o\n \tstruct transfer_request *request = request_queue_head;\n \tstruct packed_git *target;\n \n+\t/* Keep locks active */\n+\tcheck_locks();\n+\n \t/*\n \t * Don't push the object if it's known to exist on the remote\n \t * or is already in the request queue\n@@ -893,7 +900,7 @@ static struct remote_lock *lock_remote(c\n \tchar *url;\n \tchar *ep;\n \tchar timeout_header[25];\n-\tstruct remote_lock *lock = remote_locks;\n+\tstruct remote_lock *lock = NULL;\n \tXML_Parser parser = XML_ParserCreate(NULL);\n \tenum XML_Status result;\n \tstruct curl_slist *dav_headers = NULL;\n@@ -902,18 +909,6 @@ static struct remote_lock *lock_remote(c\n \turl = xmalloc(strlen(remote->url) + strlen(path) + 1);\n \tsprintf(url, \"%s%s\", remote->url, path);\n \n-\t/* Make sure the url is not already locked */\n-\twhile (lock && strcmp(lock->url, url)) {\n-\t\tlock = lock->next;\n-\t}\n-\tif (lock) {\n-\t\tfree(url);\n-\t\tif (refresh_lock(lock))\n-\t\t\treturn lock;\n-\t\telse\n-\t\t\treturn NULL;\n-\t}\n-\n \t/* Make sure leading directories exist for the remote ref */\n \tep = strchr(url + strlen(remote->url) + 11, '/');\n \twhile (ep) {\n@@ -971,10 +966,7 @@ static struct remote_lock *lock_remote(c\n \tcurl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, dav_headers);\n \n \tlock = xcalloc(1, sizeof(*lock));\n-\tlock->owner = NULL;\n-\tlock->token = NULL;\n \tlock->timeout = -1;\n-\tlock->refreshing = 0;\n \n \tif (start_active_slot(slot)) {\n \t\trun_active_slot(slot);\n@@ -1016,10 +1008,9 @@ static struct remote_lock *lock_remote(c\n \t\tlock = NULL;\n \t} else {\n \t\tlock->url = url;\n-\t\tlock->active = 1;\n \t\tlock->start_time = time(NULL);\n-\t\tlock->next = remote_locks;\n-\t\tremote_locks = lock;\n+\t\tlock->next = remote->locks;\n+\t\tremote->locks = lock;\n \t}\n \n \treturn lock;\n@@ -1029,6 +1020,7 @@ static int unlock_remote(struct remote_l\n {\n \tstruct active_request_slot *slot;\n \tstruct slot_results results;\n+\tstruct remote_lock *prev = remote->locks;\n \tchar *lock_token_header;\n \tstruct curl_slist *dav_headers = NULL;\n \tint rc = 0;\n@@ -1050,16 +1042,29 @@ static int unlock_remote(struct remote_l\n \t\tif (results.curl_result == CURLE_OK)\n \t\t\trc = 1;\n \t\telse\n-\t\t\tfprintf(stderr, \"Got HTTP error %ld\\n\",\n+\t\t\tfprintf(stderr, \"UNLOCK HTTP error %ld\\n\",\n \t\t\t\tresults.http_code);\n \t} else {\n-\t\tfprintf(stderr, \"Unable to start request\\n\");\n+\t\tfprintf(stderr, \"Unable to start UNLOCK request\\n\");\n \t}\n \n \tcurl_slist_free_all(dav_headers);\n \tfree(lock_token_header);\n \n-\tlock->active = 0;\n+\tif (remote->locks == lock) {\n+\t\tremote->locks = lock->next;\n+\t} else {\n+\t\twhile (prev && prev->next != lock)\n+\t\t\tprev = prev->next;\n+\t\tif (prev)\n+\t\t\tprev->next = prev->next->next;\t\t\t\n+\t}\n+\n+\tif (lock->owner != NULL)\n+\t\tfree(lock->owner);\n+\tfree(lock->url);\n+\tfree(lock->token);\n+\tfree(lock);\n \n \treturn rc;\n }\n@@ -1597,7 +1602,7 @@ int main(int argc, char **argv)\n \tstruct transfer_request *next_request;\n \tint nr_refspec = 0;\n \tchar **refspec = NULL;\n-\tstruct remote_lock *ref_lock;\n+\tstruct remote_lock *ref_lock = NULL;\n \tstruct rev_info revs;\n \tint rc = 0;\n \tint i;\n@@ -1605,10 +1610,7 @@ int main(int argc, char **argv)\n \tsetup_git_directory();\n \tsetup_ident();\n \n-\tremote = xmalloc(sizeof(*remote));\n-\tremote->url = NULL;\n-\tremote->path_len = 0;\n-\tremote->packs = NULL;\n+\tremote = xcalloc(sizeof(*remote), 1);\n \n \targv++;\n \tfor (i = 1; i < argc; i++, argv++) {\n@@ -1787,6 +1789,7 @@ int main(int argc, char **argv)\n \t\tif (!rc)\n \t\t\tfprintf(stderr, \"    done\\n\");\n \t\tunlock_remote(ref_lock);\n+\t\tcheck_locks();\n \t}\n \n  cleanup:\n-- \n1.2.4.g8e81-dirty\n"}]}