{"thread":{"id":"36823","subject":"[PATCH] refs.c: change read_ref_at to use the reflog iterators","startedAt":"2014-06-03T16:09:59Z","lastAt":"2014-06-03T16:09:59Z","messageCount":1,"participants":["Ronnie Sahlberg"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"243191","messageId":"1401811799-5332-1-git-send-email-sahlberg@google.com","threadId":"36823","inReplyTo":null,"subject":"[PATCH] refs.c: change read_ref_at to use the reflog iterators","fromName":"Ronnie Sahlberg","fromEmail":"sahlberg@google.com","sentAt":"2014-06-03T16:09:59Z","receivedAt":"2014-06-03T16:09:59Z","isPatch":true,"sender":{"key":"sahlberg@google.com","avatar":"https://avatars.githubusercontent.com/u/7320636?v=4"},"body":"read_ref_at has its own parsing of the reflog file for no really good reason\nso lets change this to use the existing reflog iterators. This removes one\ninstance where we manually unmarshall the reflog file format.\n\nRemove the now redundant ref_msg function.\n\nLog messages for errors are changed slightly. We no longer print the file\nname for the reflog, instead we refer to it as 'Log for ref <refname>'.\nThis might be a minor useability regression, but I don't really think so, since\nexperienced users would know where the log is anyway and inexperienced users\nwould not know what to do about/how to repair 'Log ... has gap ...' anyway.\n\nAdapt the t1400 test to handle the change in log messages.\n\nSigned-off-by: Ronnie Sahlberg <sahlberg@google.com>\n---\n refs.c                | 208 +++++++++++++++++++++++++-------------------------\n t/t1400-update-ref.sh |   4 +-\n 2 files changed, 105 insertions(+), 107 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 6898263..29eb7eb 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2926,119 +2926,117 @@ int create_symref(const char *ref_target, const char *refs_heads_master,\n \treturn 0;\n }\n \n-static char *ref_msg(const char *line, const char *endp)\n-{\n-\tconst char *ep;\n-\tline += 82;\n-\tep = memchr(line, '\\n', endp - line);\n-\tif (!ep)\n-\t\tep = endp;\n-\treturn xmemdupz(line, ep - line);\n+struct read_ref_at_cb {\n+\tconst char *refname;\n+\tunsigned long at_time;\n+\tint cnt;\n+\tint reccnt;\n+\tunsigned char *sha1;\n+\tint found_it;\n+\n+\tunsigned char osha1[20];\n+\tunsigned char nsha1[20];\n+\tint tz;\n+\tunsigned long date;\n+\tchar **msg;\n+\tunsigned long *cutoff_time;\n+\tint *cutoff_tz;\n+\tint *cutoff_cnt;\n+};\n+\n+static int read_ref_at_ent(unsigned char *osha1, unsigned char *nsha1,\n+\t\tconst char *email, unsigned long timestamp, int tz,\n+\t\tconst char *message, void *cb_data)\n+{\n+\tstruct read_ref_at_cb *cb = cb_data;\n+\n+\tcb->reccnt++;\n+\tcb->tz = tz;\n+\tcb->date = timestamp;\n+\n+\tif (timestamp <= cb->at_time || cb->cnt == 0) {\n+\t\tif (cb->msg)\n+\t\t\t*cb->msg = xstrdup(message);\n+\t\tif (cb->cutoff_time)\n+\t\t\t*cb->cutoff_time = timestamp;\n+\t\tif (cb->cutoff_tz)\n+\t\t\t*cb->cutoff_tz = tz;\n+\t\tif (cb->cutoff_cnt)\n+\t\t\t*cb->cutoff_cnt = cb->reccnt - 1;\n+\t\t/*\n+\t\t * we have not yet updated cb->[n|o]sha1 so they still\n+\t\t * hold the values for the previous record.\n+\t\t */\n+\t\tif (!is_null_sha1(cb->osha1)) {\n+\t\t\thashcpy(cb->sha1, nsha1);\n+\t\t\tif (hashcmp(cb->osha1, nsha1))\n+\t\t\t\twarning(\"Log for ref %s has gap after %s.\",\n+\t\t\t\t\tcb->refname, show_date(cb->date, cb->tz, DATE_RFC2822));\n+\t\t}\n+\t\telse if (cb->date == cb->at_time)\n+\t\t\thashcpy(cb->sha1, nsha1);\n+\t\telse if (hashcmp(nsha1, cb->sha1))\n+\t\t\twarning(\"Log for ref %s unexpectedly ended on %s.\",\n+\t\t\t\tcb->refname, show_date(cb->date, cb->tz,\n+\t\t\t\t\t\t   DATE_RFC2822));\n+\t\thashcpy(cb->osha1, osha1);\n+\t\thashcpy(cb->nsha1, nsha1);\n+\t\tcb->found_it = 1;\n+\t\treturn 1;\n+\t}\n+\thashcpy(cb->osha1, osha1);\n+\thashcpy(cb->nsha1, nsha1);\n+\tif (cb->cnt > 0)\n+\t\tcb->cnt--;\n+\treturn 0;\n+}\n+\n+static int read_ref_at_ent_oldest(unsigned char *osha1, unsigned char *nsha1,\n+\t\t\t\t  const char *email, unsigned long timestamp,\n+\t\t\t\t  int tz, const char *message, void *cb_data)\n+{\n+\tstruct read_ref_at_cb *cb = cb_data;\n+\n+\tif (cb->msg)\n+\t\t*cb->msg = xstrdup(message);\n+\tif (cb->cutoff_time)\n+\t\t*cb->cutoff_time = timestamp;\n+\tif (cb->cutoff_tz)\n+\t\t*cb->cutoff_tz = tz;\n+\tif (cb->cutoff_cnt)\n+\t\t*cb->cutoff_cnt = cb->reccnt;\n+\thashcpy(cb->sha1, osha1);\n+\tif (is_null_sha1(cb->sha1))\n+\t\thashcpy(cb->sha1, nsha1);\n+\t/* We just want the first entry */\n+\treturn 1;\n }\n \n int read_ref_at(const char *refname, unsigned long at_time, int cnt,\n \t\tunsigned char *sha1, char **msg,\n \t\tunsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt)\n {\n-\tconst char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec;\n-\tchar *tz_c;\n-\tint logfd, tz, reccnt = 0;\n-\tstruct stat st;\n-\tunsigned long date;\n-\tunsigned char logged_sha1[20];\n-\tvoid *log_mapped;\n-\tsize_t mapsz;\n+\tstruct read_ref_at_cb cb;\n \n-\tlogfile = git_path(\"logs/%s\", refname);\n-\tlogfd = open(logfile, O_RDONLY, 0);\n-\tif (logfd < 0)\n-\t\tdie_errno(\"Unable to read log '%s'\", logfile);\n-\tfstat(logfd, &st);\n-\tif (!st.st_size)\n-\t\tdie(\"Log %s is empty.\", logfile);\n-\tmapsz = xsize_t(st.st_size);\n-\tlog_mapped = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, logfd, 0);\n-\tlogdata = log_mapped;\n-\tclose(logfd);\n+\tmemset(&cb, 0, sizeof(cb));\n+\tcb.refname = refname;\n+\tcb.at_time = at_time;\n+\tcb.cnt = cnt;\n+\tcb.msg = msg;\n+\tcb.cutoff_time = cutoff_time;\n+\tcb.cutoff_tz = cutoff_tz;\n+\tcb.cutoff_cnt = cutoff_cnt;\n+\tcb.sha1 = sha1;\n+\n+\tfor_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);\n+\n+\tif (!cb.reccnt)\n+\t\tdie(\"Log for %s is empty.\", refname);\n+\tif (cb.found_it)\n+\t\treturn 0;\n+\n+\tfor_each_reflog_ent(refname, read_ref_at_ent_oldest, &cb);\n \n-\tlastrec = NULL;\n-\trec = logend = logdata + st.st_size;\n-\twhile (logdata < rec) {\n-\t\treccnt++;\n-\t\tif (logdata < rec && *(rec-1) == '\\n')\n-\t\t\trec--;\n-\t\tlastgt = NULL;\n-\t\twhile (logdata < rec && *(rec-1) != '\\n') {\n-\t\t\trec--;\n-\t\t\tif (*rec == '>')\n-\t\t\t\tlastgt = rec;\n-\t\t}\n-\t\tif (!lastgt)\n-\t\t\tdie(\"Log %s is corrupt.\", logfile);\n-\t\tdate = strtoul(lastgt + 1, &tz_c, 10);\n-\t\tif (date <= at_time || cnt == 0) {\n-\t\t\ttz = strtoul(tz_c, NULL, 10);\n-\t\t\tif (msg)\n-\t\t\t\t*msg = ref_msg(rec, logend);\n-\t\t\tif (cutoff_time)\n-\t\t\t\t*cutoff_time = date;\n-\t\t\tif (cutoff_tz)\n-\t\t\t\t*cutoff_tz = tz;\n-\t\t\tif (cutoff_cnt)\n-\t\t\t\t*cutoff_cnt = reccnt - 1;\n-\t\t\tif (lastrec) {\n-\t\t\t\tif (get_sha1_hex(lastrec, logged_sha1))\n-\t\t\t\t\tdie(\"Log %s is corrupt.\", logfile);\n-\t\t\t\tif (get_sha1_hex(rec + 41, sha1))\n-\t\t\t\t\tdie(\"Log %s is corrupt.\", logfile);\n-\t\t\t\tif (hashcmp(logged_sha1, sha1)) {\n-\t\t\t\t\twarning(\"Log %s has gap after %s.\",\n-\t\t\t\t\t\tlogfile, show_date(date, tz, DATE_RFC2822));\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\telse if (date == at_time) {\n-\t\t\t\tif (get_sha1_hex(rec + 41, sha1))\n-\t\t\t\t\tdie(\"Log %s is corrupt.\", logfile);\n-\t\t\t}\n-\t\t\telse {\n-\t\t\t\tif (get_sha1_hex(rec + 41, logged_sha1))\n-\t\t\t\t\tdie(\"Log %s is corrupt.\", logfile);\n-\t\t\t\tif (hashcmp(logged_sha1, sha1)) {\n-\t\t\t\t\twarning(\"Log %s unexpectedly ended on %s.\",\n-\t\t\t\t\t\tlogfile, show_date(date, tz, DATE_RFC2822));\n-\t\t\t\t}\n-\t\t\t}\n-\t\t\tmunmap(log_mapped, mapsz);\n-\t\t\treturn 0;\n-\t\t}\n-\t\tlastrec = rec;\n-\t\tif (cnt > 0)\n-\t\t\tcnt--;\n-\t}\n-\n-\trec = logdata;\n-\twhile (rec < logend && *rec != '>' && *rec != '\\n')\n-\t\trec++;\n-\tif (rec == logend || *rec == '\\n')\n-\t\tdie(\"Log %s is corrupt.\", logfile);\n-\tdate = strtoul(rec + 1, &tz_c, 10);\n-\ttz = strtoul(tz_c, NULL, 10);\n-\tif (get_sha1_hex(logdata, sha1))\n-\t\tdie(\"Log %s is corrupt.\", logfile);\n-\tif (is_null_sha1(sha1)) {\n-\t\tif (get_sha1_hex(logdata + 41, sha1))\n-\t\t\tdie(\"Log %s is corrupt.\", logfile);\n-\t}\n-\tif (msg)\n-\t\t*msg = ref_msg(logdata, logend);\n-\tmunmap(log_mapped, mapsz);\n-\n-\tif (cutoff_time)\n-\t\t*cutoff_time = date;\n-\tif (cutoff_tz)\n-\t\t*cutoff_tz = tz;\n-\tif (cutoff_cnt)\n-\t\t*cutoff_cnt = reccnt;\n \treturn 1;\n }\n \ndiff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh\nindex 4e2459a..0218e96 100755\n--- a/t/t1400-update-ref.sh\n+++ b/t/t1400-update-ref.sh\n@@ -235,7 +235,7 @@ test_expect_success \\\n \t'rm -f o e &&\n \t git rev-parse --verify \"master@{2005-05-26 23:33:01}\" >o 2>e &&\n \t test '\"$B\"' = $(cat o) &&\n-\t test \"warning: Log .git/logs/'\"$m has gap after $gd\"'.\" = \"$(cat e)\"'\n+\t test \"warning: Log for ref '\"$m has gap after $gd\"'.\" = \"$(cat e)\"'\n test_expect_success \\\n \t'Query \"master@{2005-05-26 23:38:00}\" (middle of history)' \\\n \t'rm -f o e &&\n@@ -253,7 +253,7 @@ test_expect_success \\\n \t'rm -f o e &&\n \t git rev-parse --verify \"master@{2005-05-28}\" >o 2>e &&\n \t test '\"$D\"' = $(cat o) &&\n-\t test \"warning: Log .git/logs/'\"$m unexpectedly ended on $ld\"'.\" = \"$(cat e)\"'\n+\t test \"warning: Log for ref '\"$m unexpectedly ended on $ld\"'.\" = \"$(cat e)\"'\n \n \n rm -f .git/$m .git/logs/$m expect\n-- \n2.0.0.527.g539d2ad\n"}]}