{"thread":{"id":"7694","subject":"[PATCH 6/9] pack-objects: get rid of create_final_object_list()","startedAt":"2007-04-16T16:31:05Z","lastAt":"2007-04-16T16:31:05Z","messageCount":1,"participants":["Nicolas Pitre"],"isPatch":true,"patchVersion":1,"patchTotal":9},"messages":[{"id":"39549","messageId":"alpine.LFD.0.98.0704161230190.4504@xanadu.home","threadId":"7694","inReplyTo":null,"subject":"[PATCH 6/9] pack-objects: get rid of create_final_object_list()","fromName":"Nicolas Pitre","fromEmail":"nico@cam.org","sentAt":"2007-04-16T16:31:05Z","receivedAt":"2007-04-16T16:31:05Z","isPatch":true,"sender":{"key":"nico@fluxnic.net","avatar":"https://avatars.githubusercontent.com/u/702790?v=4"},"body":"Because we don't have to know the SHA1 h(hence the name) of the pack\nup front anymore, let's get rid of yet another global sorted object list\nand sort them only in write_index_file(), then compute the object list\nSHA1 on the fly.\n\nThis has the advantage of saving another chunk of memory, and the sorted\nlist SHA1 won't be computed needlessly on servers during a fetch.\n\nOf course the cunning plan is also to make write_index_file() much like\nthe function with the same name in index-pack.c for an eventual easy\nsharing.\n\nSigned-off-by: Nicolas Pitre <nico@cam.org>\n---\n builtin-pack-objects.c |  127 +++++++++++++++++++++++++++---------------------\n 1 files changed, 72 insertions(+), 55 deletions(-)\n\ndiff --git a/builtin-pack-objects.c b/builtin-pack-objects.c\nindex c2f7c30..7af1776 100644\n--- a/builtin-pack-objects.c\n+++ b/builtin-pack-objects.c\n@@ -59,17 +59,16 @@ struct object_entry {\n  * heuristics.\n  */\n \n-static unsigned char object_list_sha1[20];\n static int non_empty;\n static int no_reuse_delta;\n static int local;\n static int incremental;\n static int allow_ofs_delta;\n \n-static struct object_entry **sorted_by_sha;\n static struct object_entry *objects;\n static uint32_t nr_objects, nr_alloc, nr_result;\n-static const char *base_name;\n+static const char *pack_tmp_name, *idx_tmp_name;\n+static char tmpname[PATH_MAX];\n static unsigned char pack_file_sha1[20];\n static int progress = 1;\n static volatile sig_atomic_t progress_update;\n@@ -578,13 +577,19 @@ static off_t write_pack_file(void)\n \tunsigned last_percent = 999;\n \tint do_progress = progress;\n \n-\tif (!base_name) {\n+\tif (pack_to_stdout) {\n \t\tf = sha1fd(1, \"<stdout>\");\n \t\tdo_progress >>= 1;\n+\t} else {\n+\t\tint fd;\n+\t\tsnprintf(tmpname, sizeof(tmpname), \"tmp_pack_XXXXXX\");\n+\t\tfd = mkstemp(tmpname);\n+\t\tif (fd < 0)\n+\t\t\tdie(\"unable to create %s: %s\\n\", tmpname, strerror(errno));\n+\t\tpack_tmp_name = xstrdup(tmpname);\n+\t\tf = sha1fd(fd, pack_tmp_name);\n \t}\n-\telse\n-\t\tf = sha1create(\"%s-%s.%s\", base_name,\n-\t\t\t       sha1_to_hex(object_list_sha1), \"pack\");\n+\n \tif (do_progress)\n \t\tfprintf(stderr, \"Writing %u objects.\\n\", nr_result);\n \n@@ -618,18 +623,46 @@ static off_t write_pack_file(void)\n \treturn last_obj_offset;\n }\n \n+static int sha1_sort(const void *_a, const void *_b)\n+{\n+\tconst struct object_entry *a = *(struct object_entry **)_a;\n+\tconst struct object_entry *b = *(struct object_entry **)_b;\n+\treturn hashcmp(a->sha1, b->sha1);\n+}\n+\n static uint32_t index_default_version = 1;\n static uint32_t index_off32_limit = 0x7fffffff;\n \n-static void write_index_file(off_t last_obj_offset)\n+static void write_index_file(off_t last_obj_offset, unsigned char *sha1)\n {\n-\tuint32_t i;\n-\tstruct sha1file *f = sha1create(\"%s-%s.%s\", base_name,\n-\t\t\t\t\tsha1_to_hex(object_list_sha1), \"idx\");\n-\tstruct object_entry **list = sorted_by_sha;\n-\tstruct object_entry **last = list + nr_result;\n+\tstruct sha1file *f;\n+\tstruct object_entry **sorted_by_sha, **list, **last;\n \tuint32_t array[256];\n-\tuint32_t index_version;\n+\tuint32_t i, index_version;\n+\tSHA_CTX ctx;\n+\tint fd;\n+\n+\tsnprintf(tmpname, sizeof(tmpname), \"tmp_idx_XXXXXX\");\n+\tfd = mkstemp(tmpname);\n+\tif (fd < 0)\n+\t\tdie(\"unable to create %s: %s\\n\", tmpname, strerror(errno));\n+\tidx_tmp_name = xstrdup(tmpname);\n+\tf = sha1fd(fd, idx_tmp_name);\n+\n+\tif (nr_result) {\n+\t\tuint32_t j = 0;\n+\t\tsorted_by_sha =\n+\t\t\txcalloc(nr_result, sizeof(struct object_entry *));\n+\t\tfor (i = 0; i < nr_objects; i++)\n+\t\t\tif (!objects[i].preferred_base)\n+\t\t\t\tsorted_by_sha[j++] = objects + i;\n+\t\tif (j != nr_result)\n+\t\t\tdie(\"listed %u objects while expecting %u\", j, nr_result);\n+\t\tqsort(sorted_by_sha, nr_result, sizeof(*sorted_by_sha), sha1_sort);\n+\t\tlist = sorted_by_sha;\n+\t\tlast = sorted_by_sha + nr_result;\n+\t} else\n+\t\tsorted_by_sha = list = last = NULL;\n \n \t/* if last object's offset is >= 2^31 we should use index V2 */\n \tindex_version = (last_obj_offset >> 31) ? 2 : index_default_version;\n@@ -660,9 +693,10 @@ static void write_index_file(off_t last_obj_offset)\n \t}\n \tsha1write(f, array, 256 * 4);\n \n-\t/*\n-\t * Write the actual SHA1 entries..\n-\t */\n+\t/* Compute the SHA1 hash of sorted object names. */\n+\tSHA1_Init(&ctx);\n+\n+\t/* Write the actual SHA1 entries. */\n \tlist = sorted_by_sha;\n \tfor (i = 0; i < nr_result; i++) {\n \t\tstruct object_entry *entry = *list++;\n@@ -671,6 +705,7 @@ static void write_index_file(off_t last_obj_offset)\n \t\t\tsha1write(f, &offset, 4);\n \t\t}\n \t\tsha1write(f, entry->sha1, 20);\n+\t\tSHA1_Update(&ctx, entry->sha1, 20);\n \t}\n \n \tif (index_version >= 2) {\n@@ -711,6 +746,8 @@ static void write_index_file(off_t last_obj_offset)\n \n \tsha1write(f, pack_file_sha1, 20);\n \tsha1close(f, NULL, 1);\n+\tfree(sorted_by_sha);\n+\tSHA1_Final(sha1, &ctx);\n }\n \n static int locate_object_entry_hash(const unsigned char *sha1)\n@@ -789,6 +826,8 @@ static int add_object_entry(const unsigned char *sha1, unsigned hash, int exclud\n \tif (ix >= 0) {\n \t\tif (exclude) {\n \t\t\tentry = objects + object_ix[ix] - 1;\n+\t\t\tif (!entry->preferred_base)\n+\t\t\t\tnr_result--;\n \t\t\tentry->preferred_base = 1;\n \t\t}\n \t\treturn 0;\n@@ -821,6 +860,8 @@ static int add_object_entry(const unsigned char *sha1, unsigned hash, int exclud\n \tentry->hash = hash;\n \tif (exclude)\n \t\tentry->preferred_base = 1;\n+\telse\n+\t\tnr_result++;\n \tif (found_pack) {\n \t\tentry->in_pack = found_pack;\n \t\tentry->in_pack_offset = found_offset;\n@@ -1181,30 +1222,6 @@ static void get_object_details(void)\n \t\tcheck_object(entry);\n }\n \n-static int sha1_sort(const void *_a, const void *_b)\n-{\n-\tconst struct object_entry *a = *(struct object_entry **)_a;\n-\tconst struct object_entry *b = *(struct object_entry **)_b;\n-\treturn hashcmp(a->sha1, b->sha1);\n-}\n-\n-static struct object_entry **create_final_object_list(void)\n-{\n-\tstruct object_entry **list;\n-\tuint32_t i, j;\n-\n-\tfor (i = nr_result = 0; i < nr_objects; i++)\n-\t\tif (!objects[i].preferred_base)\n-\t\t\tnr_result++;\n-\tlist = xmalloc(nr_result * sizeof(struct object_entry *));\n-\tfor (i = j = 0; i < nr_objects; i++) {\n-\t\tif (!objects[i].preferred_base)\n-\t\t\tlist[j++] = objects + i;\n-\t}\n-\tqsort(list, nr_result, sizeof(struct object_entry *), sha1_sort);\n-\treturn list;\n-}\n-\n static int type_size_sort(const void *_a, const void *_b)\n {\n \tconst struct object_entry *a = *(struct object_entry **)_a;\n@@ -1561,13 +1578,12 @@ static void get_object_list(int ac, const char **av)\n \n int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n {\n-\tSHA_CTX ctx;\n \tint depth = 10;\n-\tstruct object_entry **list;\n-\toff_t last_obj_offset;\n \tint use_internal_rev_list = 0;\n \tint thin = 0;\n \tuint32_t i;\n+\toff_t last_obj_offset;\n+\tconst char *base_name = NULL;\n \tconst char **rp_av;\n \tint rp_ac_alloc = 64;\n \tint rp_ac;\n@@ -1712,20 +1728,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n \n \tif (progress)\n \t\tfprintf(stderr, \"Done counting %u objects.\\n\", nr_objects);\n-\tsorted_by_sha = create_final_object_list();\n \tif (non_empty && !nr_result)\n \t\treturn 0;\n-\n-\tSHA1_Init(&ctx);\n-\tlist = sorted_by_sha;\n-\tfor (i = 0; i < nr_result; i++) {\n-\t\tstruct object_entry *entry = *list++;\n-\t\tSHA1_Update(&ctx, entry->sha1, 20);\n-\t}\n-\tSHA1_Final(object_list_sha1, &ctx);\n \tif (progress && (nr_objects != nr_result))\n \t\tfprintf(stderr, \"Result has %u objects.\\n\", nr_result);\n-\n \tif (nr_result)\n \t\tprepare_pack(window, depth);\n \tif (progress == 1 && pack_to_stdout) {\n@@ -1737,7 +1743,18 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)\n \t}\n \tlast_obj_offset = write_pack_file();\n \tif (!pack_to_stdout) {\n-\t\twrite_index_file(last_obj_offset);\n+\t\tunsigned char object_list_sha1[20];\n+\t\twrite_index_file(last_obj_offset, object_list_sha1);\n+\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.pack\",\n+\t\t\t base_name, sha1_to_hex(object_list_sha1));\n+\t\tif (rename(pack_tmp_name, tmpname))\n+\t\t\tdie(\"unable to rename temporary pack file: %s\",\n+\t\t\t    strerror(errno));\n+\t\tsnprintf(tmpname, sizeof(tmpname), \"%s-%s.idx\",\n+\t\t\t base_name, sha1_to_hex(object_list_sha1));\n+\t\tif (rename(idx_tmp_name, tmpname))\n+\t\t\tdie(\"unable to rename temporary index file: %s\",\n+\t\t\t    strerror(errno));\n \t\tputs(sha1_to_hex(object_list_sha1));\n \t}\n \tif (progress)\n-- \n1.5.1.1.781.g65e8\n"}]}