aboutsummaryrefslogtreecommitdiff
path: root/refs.c
diff options
context:
space:
mode:
authorShawn Pearce <spearce@spearce.org>2006-05-19 03:28:19 -0400
committerJunio C Hamano <junkio@cox.net>2006-05-19 15:02:32 -0700
commite52290428b5b6f55cb7bb7a4624751750241d5aa (patch)
tree94fd2924dcc4d37179c5e6976c5e9b89ad83a937 /refs.c
parent70e34b2dc88e28f09903b85932ea679992da62ff (diff)
downloadgit-e52290428b5b6f55cb7bb7a4624751750241d5aa.tar.gz
git-e52290428b5b6f55cb7bb7a4624751750241d5aa.tar.xz
General ref log reading improvements.
Corrected the log starting time displayed in the error message (as it was always showing the epoch due to a bad input to strtoul). Improved the log parser so we only scan backwards towards the '\n' from the end of the prior log; during this scan the last '>' is remembered to improve performance (rather than scanning forward to it). If the log record matched is the last log record in the file only use its new sha1 value if the date matches exactly; otherwise we leave the passed in sha1 alone as it already contains the current value of the ref. This way lookups of dates later than the log end to stick with the current ref value in case the ref was updated without logging. If it looks like someone changed the ref without logging it and we are going to return the sha1 which should have been valid during the missing period then warn the user that there might be log data missing and thus their query result may not be accurate. The check isn't perfect as its just based on comparing the old and new sha1 values between the two log records but its better than not checking at all. Implemented test cases based on git-rev-parse for most of the boundary conditions. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'refs.c')
-rw-r--r--refs.c54
1 files changed, 40 insertions, 14 deletions
diff --git a/refs.c b/refs.c
index ae9825dea..9d37a028c 100644
--- a/refs.c
+++ b/refs.c
@@ -432,11 +432,12 @@ int write_ref_sha1(struct ref_lock *lock,
int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1)
{
- const char *logfile, *logdata, *logend, *rec, *c;
+ const char *logfile, *logdata, *logend, *rec, *lastgt, *lastrec;
char *tz_c;
int logfd, tz;
struct stat st;
unsigned long date;
+ unsigned char logged_sha1[20];
logfile = git_path("logs/%s", ref);
logfd = open(logfile, O_RDONLY, 0);
@@ -448,32 +449,57 @@ int read_ref_at(const char *ref, unsigned long at_time, unsigned char *sha1)
logdata = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, logfd, 0);
close(logfd);
+ lastrec = NULL;
rec = logend = logdata + st.st_size;
while (logdata < rec) {
if (logdata < rec && *(rec-1) == '\n')
rec--;
- while (logdata < rec && *(rec-1) != '\n')
+ lastgt = NULL;
+ while (logdata < rec && *(rec-1) != '\n') {
rec--;
- c = rec;
- while (c < logend && *c != '>' && *c != '\n')
- c++;
- if (c == logend || *c == '\n')
+ if (*rec == '>')
+ lastgt = rec;
+ }
+ if (!lastgt)
die("Log %s is corrupt.", logfile);
- date = strtoul(c + 1, NULL, 10);
+ date = strtoul(lastgt + 1, &tz_c, 10);
if (date <= at_time) {
- if (get_sha1_hex(rec + 41, sha1))
- die("Log %s is corrupt.", logfile);
+ if (lastrec) {
+ if (get_sha1_hex(lastrec, logged_sha1))
+ die("Log %s is corrupt.", logfile);
+ if (get_sha1_hex(rec + 41, sha1))
+ die("Log %s is corrupt.", logfile);
+ if (memcmp(logged_sha1, sha1, 20)) {
+ tz = strtoul(tz_c, NULL, 10);
+ fprintf(stderr,
+ "warning: Log %s has gap after %s.\n",
+ logfile, show_rfc2822_date(date, tz));
+ }
+ } else if (date == at_time) {
+ if (get_sha1_hex(rec + 41, sha1))
+ die("Log %s is corrupt.", logfile);
+ } else {
+ if (get_sha1_hex(rec + 41, logged_sha1))
+ die("Log %s is corrupt.", logfile);
+ if (memcmp(logged_sha1, sha1, 20)) {
+ tz = strtoul(tz_c, NULL, 10);
+ fprintf(stderr,
+ "warning: Log %s unexpectedly ended on %s.\n",
+ logfile, show_rfc2822_date(date, tz));
+ }
+ }
munmap((void*)logdata, st.st_size);
return 0;
}
+ lastrec = rec;
}
- c = logdata;
- while (c < logend && *c != '>' && *c != '\n')
- c++;
- if (c == logend || *c == '\n')
+ rec = logdata;
+ while (rec < logend && *rec != '>' && *rec != '\n')
+ rec++;
+ if (rec == logend || *rec == '\n')
die("Log %s is corrupt.", logfile);
- date = strtoul(c, &tz_c, 10);
+ date = strtoul(rec + 1, &tz_c, 10);
tz = strtoul(tz_c, NULL, 10);
if (get_sha1_hex(logdata, sha1))
die("Log %s is corrupt.", logfile);