Mercurial > hg > mercurial-crew-with-dirclash
changeset 5372:6f6aa7f3bc1c
Merge with crew
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Thu, 04 Oct 2007 19:47:22 -0500 |
parents | 17ed9b9a0d03 (diff) 6b72ceef7472 (current diff) |
children | 6aba1835a7b3 |
files | |
diffstat | 15 files changed, 154 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/bdiff.c +++ b/mercurial/bdiff.c @@ -12,6 +12,7 @@ #include <Python.h> #include <stdlib.h> #include <string.h> +#include <limits.h> #if defined __hpux || defined __SUNPRO_C || defined _AIX # define inline @@ -58,21 +59,17 @@ struct hunklist { struct hunk *base, *head; }; -static inline uint32_t rol32(uint32_t word, unsigned int shift) -{ - return (word << shift) | (word >> (32 - shift)); -} - int splitlines(const char *a, int len, struct line **lr) { - int g, h, i; + int h, i; const char *p, *b = a; + const char * const plast = a + len - 1; struct line *l; /* count the lines */ i = 1; /* extra line for sentinel */ for (p = a; p < a + len; p++) - if (*p == '\n' || p == a + len - 1) + if (*p == '\n' || p == plast) i++; *lr = l = (struct line *)malloc(sizeof(struct line) * i); @@ -82,24 +79,17 @@ int splitlines(const char *a, int len, s /* build the line array and calculate hashes */ h = 0; for (p = a; p < a + len; p++) { - /* - * a simple hash from GNU diff, with better collision - * resistance from hashpjw. this slows down common - * case by 10%, but speeds up worst case by 100x. - */ - h = *p + rol32(h, 7); - if ((g = h & 0xf0000000)) { - h ^= g >> 24; - h ^= g; - } - if (*p == '\n' || p == a + len - 1) { + /* Leonid Yuriev's hash */ + h = (h * 1664525) + *p + 1013904223; + + if (*p == '\n' || p == plast) { + l->h = h; + h = 0; l->len = p - b + 1; - l->h = h * l->len; l->l = b; - l->n = -1; + l->n = INT_MAX; l++; b = p + 1; - h = 0; } } @@ -117,27 +107,34 @@ int inline cmp(struct line *a, struct li static int equatelines(struct line *a, int an, struct line *b, int bn) { int i, j, buckets = 1, t; + int scale = 32; struct pos *h; /* build a hash table of the next highest power of 2 */ while (buckets < bn + 1) buckets *= 2; - h = (struct pos *)malloc(buckets * sizeof(struct pos)); - buckets = buckets - 1; + /* try to allocate a large hash table to avoid collisions */ + do { + scale /= 2; + h = (struct pos *)malloc(scale * buckets * sizeof(struct pos)); + } while (!h && scale != 1); + if (!h) return 0; + buckets = buckets * scale - 1; + /* clear the hash table */ for (i = 0; i <= buckets; i++) { - h[i].pos = -1; + h[i].pos = INT_MAX; h[i].len = 0; } /* add lines to the hash table chains */ for (i = bn - 1; i >= 0; i--) { /* find the equivalence class */ - for (j = b[i].h & buckets; h[j].pos != -1; + for (j = b[i].h & buckets; h[j].pos != INT_MAX; j = (j + 1) & buckets) if (!cmp(b + i, b + h[j].pos)) break; @@ -155,7 +152,7 @@ static int equatelines(struct line *a, i /* match items in a to their equivalence class in b */ for (i = 0; i < an; i++) { /* find the equivalence class */ - for (j = a[i].h & buckets; h[j].pos != -1; + for (j = a[i].h & buckets; h[j].pos != INT_MAX; j = (j + 1) & buckets) if (!cmp(a + i, b + h[j].pos)) break; @@ -164,7 +161,7 @@ static int equatelines(struct line *a, i if (h[j].len <= t) a[i].n = h[j].pos; /* point to head of match list */ else - a[i].n = -1; /* too popular */ + a[i].n = INT_MAX; /* too popular */ } /* discard hash tables */ @@ -179,11 +176,11 @@ static int longest_match(struct line *a, for (i = a1; i < a2; i++) { /* skip things before the current block */ - for (j = a[i].n; j != -1 && j < b1; j = b[j].n) + for (j = a[i].n; j < b1; j = b[j].n) ; /* loop through all lines match a[i] in b */ - for (; j != -1 && j < b2; j = b[j].n) { + for (; j < b2; j = b[j].n) { /* does this extend an earlier match? */ if (i > a1 && j > b1 && pos[j - 1].pos == i - 1) k = pos[j - 1].len + 1; @@ -216,6 +213,7 @@ static int longest_match(struct line *a, *omi = mi - mb; *omj = mj - mb; + return mk + mb; }
--- a/mercurial/changegroup.py +++ b/mercurial/changegroup.py @@ -33,10 +33,9 @@ def chunkiter(source): break yield c -def genchunk(data): - """build a changegroup chunk""" - header = struct.pack(">l", len(data)+ 4) - return "%s%s" % (header, data) +def chunkheader(length): + """build a changegroup chunk header""" + return struct.pack(">l", length + 4) def closechunk(): return struct.pack(">l", 0) @@ -86,7 +85,12 @@ def writebundle(cg, filename, bundletype empty = True for chunk in chunkiter(cg): empty = False - fh.write(z.compress(genchunk(chunk))) + fh.write(z.compress(chunkheader(len(chunk)))) + pos = 0 + while pos < len(chunk): + next = pos + 2**20 + fh.write(z.compress(chunk[pos:next])) + pos = next fh.write(z.compress(closechunk())) fh.write(z.flush()) cleanup = None
--- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -1720,7 +1720,8 @@ class localrepository(repo.repository): # If any filenodes are left, generate the group for them, # otherwise don't bother. if len(msng_filenode_lst) > 0: - yield changegroup.genchunk(fname) + yield changegroup.chunkheader(len(fname)) + yield fname # Sort the filenodes by their revision # msng_filenode_lst.sort(cmp_by_rev_func(filerevlog)) # Create a group generator and only pass in a changenode @@ -1796,7 +1797,8 @@ class localrepository(repo.repository): nodeiter = gennodelst(filerevlog) nodeiter = list(nodeiter) if nodeiter: - yield changegroup.genchunk(fname) + yield changegroup.chunkheader(len(fname)) + yield fname lookup = lookuprevlink_func(filerevlog) for chnk in filerevlog.group(nodeiter, lookup): yield chnk
--- a/mercurial/mdiff.py +++ b/mercurial/mdiff.py @@ -245,6 +245,9 @@ def patch(a, bin): def get_matching_blocks(a, b): return [(d[0], d[2], d[1] - d[0]) for d in bdiff.blocks(a, b)] +def trivialdiffheader(length): + return struct.pack(">lll", 0, 0, length) + patches = mpatch.patches patchedsize = mpatch.patchedsize textdiff = bdiff.bdiff
--- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -188,9 +188,18 @@ def findcopies(repo, m1, m2, ma, limit): if not m1 or not m2 or not ma: return {}, {} + repo.ui.debug(_(" searching for copies back to rev %d\n") % limit) + u1 = nonoverlap(m1, m2, ma) u2 = nonoverlap(m2, m1, ma) + if u1: + repo.ui.debug(_(" unmatched files in local:\n %s\n") + % "\n ".join(u1)) + if u2: + repo.ui.debug(_(" unmatched files in other:\n %s\n") + % "\n ".join(u2)) + for f in u1: checkcopies(ctx(f, m1[f]), m2, ma) @@ -204,9 +213,19 @@ def findcopies(repo, m1, m2, ma, limit): fo.remove(f) d2[f] = (of, fo) + if fullcopy: + repo.ui.debug(_(" all copies found (* = to merge, ! = divergent):\n")) + for f in fullcopy: + note = "" + if f in copy: note += "*" + if f in diverge: note += "!" + repo.ui.debug(_(" %s -> %s %s\n") % (f, fullcopy[f], note)) + if not fullcopy or not repo.ui.configbool("merge", "followdirs", True): return copy, diverge + repo.ui.debug(_(" checking for directory renames\n")) + # generate a directory move map d1, d2 = dirs(m1), dirs(m2) invalid = {} @@ -241,6 +260,9 @@ def findcopies(repo, m1, m2, ma, limit): if not dirmove: return copy, diverge + for d in dirmove: + repo.ui.debug(_(" dir %s -> %s\n") % (d, dirmove[d])) + # check unaccounted nonoverlapping files against directory moves for f in u1 + u2: if f not in fullcopy: @@ -248,6 +270,7 @@ def findcopies(repo, m1, m2, ma, limit): if f.startswith(d): # new file added in a directory that was moved, move it copy[f] = dirmove[d] + f[len(d):] + repo.ui.debug(_(" file %s -> %s\n") % (f, copy[f])) break return copy, diverge
--- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -1087,10 +1087,16 @@ class revlog(object): if infocollect is not None: infocollect(nb) - d = self.revdiff(a, b) p = self.parents(nb) meta = nb + p[0] + p[1] + lookup(nb) - yield changegroup.genchunk("%s%s" % (meta, d)) + if a == -1: + d = self.revision(nb) + meta += mdiff.trivialdiffheader(len(d)) + else: + d = self.revdiff(a, b) + yield changegroup.chunkheader(len(meta) + len(d)) + yield meta + yield d yield changegroup.closechunk()
--- a/tests/test-copy-move-merge.out +++ b/tests/test-copy-move-merge.out @@ -2,6 +2,14 @@ 1 files updated, 0 files merged, 2 files resolving manifests overwrite None partial False ancestor 583c7b748052 local fb3948d97f07+ remote 40da226db0f0 + searching for copies back to rev 1 + unmatched files in other: + b + c + all copies found (* = to merge, ! = divergent): + c -> a * + b -> a * + checking for directory renames a: remote moved to c -> m a: remote moved to b -> m copying a to b
--- a/tests/test-double-merge.out +++ b/tests/test-double-merge.out @@ -1,6 +1,12 @@ resolving manifests overwrite None partial False ancestor 310fd17130da local 2092631ce82b+ remote 7731dad1c2b9 + searching for copies back to rev 1 + unmatched files in other: + bar + all copies found (* = to merge, ! = divergent): + bar -> foo * + checking for directory renames foo: versions differ -> m foo: remote copied to bar -> m copying foo to bar
--- a/tests/test-issue522.out +++ b/tests/test-issue522.out @@ -4,6 +4,9 @@ 1 files updated, 0 files merged, 0 files resolving manifests overwrite None partial False ancestor bbd179dfa0a7 local 71766447bdbb+ remote 4d9e78aaceee + searching for copies back to rev 1 + unmatched files in local: + bar foo: remote is newer -> g getting foo 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-issue672.out +++ b/tests/test-issue672.out @@ -4,6 +4,12 @@ 1 files updated, 0 files merged, 1 files resolving manifests overwrite None partial False ancestor 81f4b099af3d local c64f439569a9+ remote 2f8037f47a5c + searching for copies back to rev 1 + unmatched files in other: + 1a + all copies found (* = to merge, ! = divergent): + 1a -> 1 + checking for directory renames 1: other deleted -> r 1a: remote created -> g removing 1 @@ -15,6 +21,12 @@ 1 files updated, 0 files merged, 1 files resolving manifests overwrite None partial False ancestor c64f439569a9 local ac7575e3c052+ remote 746e9549ea96 + searching for copies back to rev 1 + unmatched files in local: + 1a + all copies found (* = to merge, ! = divergent): + 1a -> 1 * + checking for directory renames 1a: local moved to 1 -> m merging 1a and 1 my 1a@ac7575e3c052+ other 1@746e9549ea96 ancestor 1@81f4b099af3d @@ -24,6 +36,12 @@ 1 files updated, 0 files merged, 1 files resolving manifests overwrite None partial False ancestor c64f439569a9 local 746e9549ea96+ remote ac7575e3c052 + searching for copies back to rev 1 + unmatched files in other: + 1a + all copies found (* = to merge, ! = divergent): + 1a -> 1 * + checking for directory renames 1: remote moved to 1a -> m copying 1 to 1a merging 1 and 1a
--- a/tests/test-merge-commit.out +++ b/tests/test-merge-commit.out @@ -23,6 +23,7 @@ 0:2665aaee66e9 resolving manifests overwrite None partial False ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 7d3b554bfdf1 + searching for copies back to rev 1 bar: versions differ -> m merging bar my bar@2d2f9a22c82b+ other bar@7d3b554bfdf1 ancestor bar@0a3ab4856510 @@ -68,6 +69,7 @@ 0:2665aaee66e9 resolving manifests overwrite None partial False ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 96ab80c60897 + searching for copies back to rev 1 bar: versions differ -> m merging bar my bar@2d2f9a22c82b+ other bar@96ab80c60897 ancestor bar@0a3ab4856510
--- a/tests/test-merge7.out +++ b/tests/test-merge7.out @@ -24,6 +24,7 @@ warning: conflicts during merge. resolving manifests overwrite None partial False ancestor faaea63e63a9 local 451c744aabcc+ remote a070d41e8360 + searching for copies back to rev 1 test.txt: versions differ -> m merging test.txt my test.txt@451c744aabcc+ other test.txt@a070d41e8360 ancestor test.txt@faaea63e63a9
--- a/tests/test-rename-dir-merge.out +++ b/tests/test-rename-dir-merge.out @@ -9,6 +9,18 @@ 2 files updated, 0 files merged, 2 files resolving manifests overwrite None partial False ancestor f9b20c0d4c51 local ce36d17b18fb+ remote 55119e611c80 + searching for copies back to rev 1 + unmatched files in local: + a/c + unmatched files in other: + b/a + b/b + all copies found (* = to merge, ! = divergent): + b/a -> a/a + b/b -> a/b + checking for directory renames + dir a/ -> b/ + file a/c -> b/c a/c: remote renamed directory to b/c -> d a/b: other deleted -> r a/a: other deleted -> r @@ -34,6 +46,18 @@ 0 files updated, 0 files merged, 1 files resolving manifests overwrite None partial False ancestor f9b20c0d4c51 local 55119e611c80+ remote ce36d17b18fb + searching for copies back to rev 1 + unmatched files in local: + b/a + b/b + unmatched files in other: + a/c + all copies found (* = to merge, ! = divergent): + b/a -> a/a + b/b -> a/b + checking for directory renames + dir a/ -> b/ + file a/c -> b/c None: local renamed directory to b/c -> d getting a/c to b/c 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-rename-merge1.out +++ b/tests/test-rename-merge1.out @@ -4,6 +4,17 @@ merge resolving manifests overwrite None partial False ancestor af1939970a1c local f26ec4fc3fa3+ remote 8e765a822af2 + searching for copies back to rev 1 + unmatched files in local: + c2 + unmatched files in other: + b + b2 + all copies found (* = to merge, ! = divergent): + c2 -> a2 + b -> a * + b2 -> a2 + checking for directory renames a2: divergent renames -> dr a: remote moved to b -> m b2: remote created -> g
--- a/tests/test-up-local-change.out +++ b/tests/test-up-local-change.out @@ -17,6 +17,9 @@ summary: 1 resolving manifests overwrite False partial False ancestor 33aaa84a386b local 33aaa84a386b+ remote 802f095af299 + searching for copies back to rev 1 + unmatched files in other: + b a: versions differ -> m b: remote created -> g merging a @@ -50,6 +53,9 @@ summary: 1 resolving manifests overwrite False partial False ancestor 33aaa84a386b local 33aaa84a386b+ remote 802f095af299 + searching for copies back to rev 1 + unmatched files in other: + b a: versions differ -> m b: remote created -> g merging a @@ -100,6 +106,7 @@ failed resolving manifests overwrite False partial False ancestor 33aaa84a386b local 802f095af299+ remote 030602aee63d + searching for copies back to rev 1 a: versions differ -> m b: versions differ -> m merging a