From 86f3195293e0fc04a8930e13107efd5e54ca8fcf Mon Sep 17 00:00:00 2001 From: Niall O'Higgins Date: Fri, 12 Jan 2007 23:32:02 +0000 Subject: major re-work of the RCS api. this results in 100x performance improvements in some places and much reduced memory usage. note that only checkout has been fully converted to use the new high-performance functions. other codepaths (e.g. update) still use the old method which is provided for backwards compatibility. we can convert the remaining slow bits over to the new api piece-by-piece. "commit this, now" joris@ brad@ tested, too. --- usr.bin/cvs/rcs.c | 428 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 414 insertions(+), 14 deletions(-) (limited to 'usr.bin/cvs/rcs.c') diff --git a/usr.bin/cvs/rcs.c b/usr.bin/cvs/rcs.c index 14d5dd7f729..1ec2c8fb66b 100644 --- a/usr.bin/cvs/rcs.c +++ b/usr.bin/cvs/rcs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rcs.c,v 1.195 2007/01/12 19:28:12 joris Exp $ */ +/* $OpenBSD: rcs.c,v 1.196 2007/01/12 23:32:01 niallo Exp $ */ /* * Copyright (c) 2004 Jean-Francois Brousseau * All rights reserved. @@ -236,6 +236,8 @@ static void rcs_growbuf(RCSFILE *); static void rcs_strprint(const u_char *, size_t, FILE *); static BUF *rcs_expand_keywords(char *, struct rcs_delta *, BUF *, int); +static void rcs_kwexp_line(char *, struct rcs_delta *, struct cvs_line *, + int mode); RCSFILE * rcs_open(const char *path, int fd, int flags, ...) @@ -1404,25 +1406,15 @@ rcs_rev_remove(RCSFILE *rf, RCSNUM *rev) newdeltatext = NULL; prevbuf = nextbuf = NULL; - if (prevrdp != NULL) { - if ((prevbuf = rcs_getrev(rf, prevrdp->rd_num)) == NULL) - fatal("error getting revision"); - } - if (prevrdp != NULL && nextrdp != NULL) { - if ((nextbuf = rcs_getrev(rf, nextrdp->rd_num)) == NULL) - fatal("error getting revision"); - newdiff = cvs_buf_alloc(64, BUF_AUTOEXT); /* calculate new diff */ (void)xasprintf(&path_tmp1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); - cvs_buf_write_stmp(nextbuf, path_tmp1, NULL); - cvs_buf_free(nextbuf); + rcs_rev_write_stmp(rf, nextrdp->rd_num, path_tmp1, 0); (void)xasprintf(&path_tmp2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); - cvs_buf_write_stmp(prevbuf, path_tmp2, NULL); - cvs_buf_free(prevbuf); + rcs_rev_write_stmp(rf, prevrdp->rd_num, path_tmp2, 0); diff_format = D_RCSDIFF; if (cvs_diffreg(path_tmp1, path_tmp2, newdiff) == D_ERROR) @@ -2600,7 +2592,6 @@ rcs_expand_keywords(char *rcsfile, struct rcs_delta *rdp, BUF *bp, int mode) u_int j, found; u_char *c, *kwstr, *start, *end, *fin; char expbuf[256], buf[256]; - struct tm tb; char *fmt; size_t len; @@ -3038,3 +3029,412 @@ rcs_translate_tag(const char *revstr, RCSFILE *rfp) return (rev); } + +/* + * rcs_rev_getlines() + * + * Get the entire contents of revision from the RCSFILE and + * return it as a pointer to a struct cvs_lines. + */ +struct cvs_lines * +rcs_rev_getlines(RCSFILE *rfp, RCSNUM *frev) +{ + size_t i, plen; + int done, nextroot, found; + RCSNUM *tnum, *bnum; + struct rcs_branch *brp; + struct rcs_delta *hrdp, *trdp, *rdp; + u_char *patch; + struct cvs_lines *dlines, *plines; + + if ((hrdp = rcs_findrev(rfp, rfp->rf_head)) == NULL) + fatal("rcs_rev_write_fd: no HEAD revision"); + + tnum = frev; + rcs_parse_deltatexts(rfp, hrdp->rd_num); + + /* revision on branch, get the branch root */ + nextroot = 2; + if (RCSNUM_ISBRANCHREV(tnum)) { + bnum = rcsnum_alloc(); + rcsnum_cpy(tnum, bnum, nextroot); + } else { + bnum = tnum; + } + + dlines = cvs_splitlines(hrdp->rd_text, hrdp->rd_tlen); + + done = 0; + + rdp = hrdp; + if (!rcsnum_differ(rdp->rd_num, bnum)) + goto next; + + if ((rdp = rcs_findrev(rfp, hrdp->rd_next)) == NULL) + goto done; + +again: + for (;;) { + if (rdp->rd_next->rn_len != 0) { + trdp = rcs_findrev(rfp, rdp->rd_next); + if (trdp == NULL) + fatal("failed to grab next revision"); + } + + if (rdp->rd_tlen == 0) { + rcs_parse_deltatexts(rfp, rdp->rd_num); + if (rdp->rd_tlen == 0) { + if (!rcsnum_differ(rdp->rd_num, bnum)) + break; + rdp = trdp; + continue; + } + } + + plen = rdp->rd_tlen; + patch = rdp->rd_text; + plines = cvs_splitlines(patch, plen); + rcs_patch_lines(dlines, plines); + cvs_freelines(plines); + + if (!rcsnum_differ(rdp->rd_num, bnum)) + break; + + rdp = trdp; + } + +next: + if (!rcsnum_differ(rdp->rd_num, frev)) + done = 1; + + if (RCSNUM_ISBRANCHREV(frev) && done != 1) { + nextroot += 2; + rcsnum_cpy(frev, bnum, nextroot); + + TAILQ_FOREACH(brp, &(rdp->rd_branches), rb_list) { + found = 1; + for (i = 0; i < nextroot - 1; i++) { + if (brp->rb_num->rn_id[i] != bnum->rn_id[i]) { + found = 0; + break; + } + } + + break; + } + + if (brp == NULL) + fatal("expected branch not found on branch list"); + + if ((rdp = rcs_findrev(rfp, brp->rb_num)) == NULL) + fatal("rcs_rev_write_fd: failed to get delta for target rev"); + + goto again; + } +done: + if (bnum != tnum) + rcsnum_free(bnum); + + return (dlines); +} + +/* + * rcs_rev_getbuf() + * + * XXX: This is really really slow and should be avoided if at all possible! + * + * Get the entire contents of revision from the RCSFILE and + * return it as a BUF pointer. + */ +BUF * +rcs_rev_getbuf(RCSFILE *rfp, RCSNUM *rev) +{ + struct cvs_lines *lines; + struct cvs_line *lp; + BUF *bp; + + lines = rcs_rev_getlines(rfp, rev); + bp = cvs_buf_alloc(1024, BUF_AUTOEXT); + TAILQ_FOREACH(lp, &lines->l_lines, l_list) { + if (lp->l_line == NULL) + continue; + cvs_buf_append(bp, lp->l_line, lp->l_len); + } + + cvs_freelines(lines); + + return (bp); +} + +/* + * rcs_rev_write_fd() + * + * Write the entire contents of revision from the rcsfile to + * file descriptor . + */ +void +rcs_rev_write_fd(RCSFILE *rfp, RCSNUM *rev, int fd, int mode) +{ + int expmode; + struct rcs_delta *rdp; + struct cvs_lines *lines; + struct cvs_line *lp; + + lines = rcs_rev_getlines(rfp, rev); + /* keyword expansion if necessary */ + if (!(mode & RCS_KWEXP_NONE)) { + if (rfp->rf_expand != NULL) + expmode = rcs_kwexp_get(rfp); + else + expmode = RCS_KWEXP_DEFAULT; + + if (!(expmode & RCS_KWEXP_NONE)) { + if ((rdp = rcs_findrev(rfp, rev)) == NULL) + fatal("could not fetch revision"); + rcs_kwexp_lines(rfp->rf_path, rdp, lines, expmode); + } + } + TAILQ_FOREACH(lp, &lines->l_lines, l_list) { + if (lp->l_line == NULL) + continue; + if (write(fd, lp->l_line, lp->l_len) == -1) + fatal("rcs_rev_write_fd: %s", strerror(errno)); + } + + /* XXX: do we need to call futimes(2) on the output fd? */ + + cvs_freelines(lines); + +} + +/* + * rcs_rev_write_stmp() + * + * Write the contents of the rev to a temporary file whose path is + * specified using