##// END OF EJS Templates
obsolescence: add test case B-6 for obsolescence markers exchange...
obsolescence: add test case B-6 for obsolescence markers exchange About 3 years ago, in August 2014, the logic to select what markers to select on push was ported from the evolve extension to Mercurial core. However, for some unclear reasons, the tests for that logic were not ported alongside. I realised it a couple of weeks ago while working on another push related issue. I've made a clean up pass on the tests and they are now ready to integrate the core test suite. This series of changesets do not change any logic. I just adds test for logic that has been around for about 10 versions of Mercurial. They are a patch for each test case. It makes it easier to review and postpone one with documentation issues without rejecting the wholes series. This patch introduce case B6: Pruned changeset with precursors not in pushed set Each test case comes it in own test file. It help parallelism and does not introduce a significant overhead from having a single unified giant test file. Here are timing to support this claim. # Multiple test files version: # run-tests.py --local -j 1 test-exchange-*.t 53.40s user 6.82s system 85% cpu 1:10.76 total 52.79s user 6.97s system 85% cpu 1:09.97 total 52.94s user 6.82s system 85% cpu 1:09.69 total # Single test file version: # run-tests.py --local -j 1 test-exchange-obsmarkers.t 52.97s user 6.85s system 85% cpu 1:10.10 total 52.64s user 6.79s system 85% cpu 1:09.63 total 53.70s user 7.00s system 85% cpu 1:11.17 total

File last commit:

r29749:155f0cc3 default
r31918:68dc2eca default
Show More
mpatch.c
280 lines | 5.9 KiB | text/x-c | CLexer
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 /*
mpatch.c - efficient binary patching for Mercurial
This implements a patch algorithm that's O(m + nlog n) where m is the
size of the output and n is the number of patches.
Given a list of binary patches, it unpacks each into a hunk list,
then combines the hunk lists with a treewise recursion to form a
single hunk list. This hunk list is then applied to the original
text.
The text (or binary) fragments are copied directly from their source
Python objects into a preallocated output string to avoid the
allocation of intermediate Python objects. Working memory is about 2x
the total number of hunks.
Vadim Gelfer
update copyrights.
r2859 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
*/
#include <stdlib.h>
#include <string.h>
Vadim Gelfer
mac os x: fixes for 10.2 from chris monson <monpublic@gmail.com>
r2468
Maciej Fijalkowski
internals: move the bitmanipulation routines into its own file...
r29444 #include "bitmanipulation.h"
Maciej Fijalkowski
mpatch: change Py_ssize_t to ssize_t in places that will be later copied
r29691 #include "compat.h"
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 #include "mpatch.h"
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
Yuya Nishihara
mpatch: change lalloc() to local function...
r29741 static struct mpatch_flist *lalloc(ssize_t size)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 struct mpatch_flist *a = NULL;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
Matt Mackall
mpatch: Fix for malloc corner case on AIX
r3138 if (size < 1)
size = 1;
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 a = (struct mpatch_flist *)malloc(sizeof(struct mpatch_flist));
mpm@selenic.com
Add safety checking to mpatch
r128 if (a) {
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 a->base = (struct mpatch_frag *)malloc(sizeof(struct mpatch_frag) * size);
Thomas Arendsen Hein
Set correct exception for another possible malloc error in mpatch.c
r2048 if (a->base) {
mpm@selenic.com
Add safety checking to mpatch
r128 a->head = a->tail = a->base;
Thomas Arendsen Hein
Set correct exception for another possible malloc error in mpatch.c
r2048 return a;
}
free(a);
mpm@selenic.com
Add safety checking to mpatch
r128 }
Benoit Boissinot
catch errors and throw exception with invalid binary patch data
r1722 return NULL;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }
Maciej Fijalkowski
mpatch: split mpatch into two files
r29693 void mpatch_lfree(struct mpatch_flist *a)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
mpm@selenic.com
Add safety checking to mpatch
r128 if (a) {
free(a->base);
free(a);
}
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 static ssize_t lsize(struct mpatch_flist *a)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
return a->tail - a->head;
}
/* move hunks in source that are less cut to dest, compensating
for changes in offset. the last hunk may be split if necessary.
*/
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 static int gather(struct mpatch_flist *dest, struct mpatch_flist *src, int cut,
int offset)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 struct mpatch_frag *d = dest->tail, *s = src->head;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 int postend, c, l;
while (s != src->tail) {
if (s->start + offset >= cut)
mpm@selenic.com
Gotos are embarrassing.
r82 break; /* we've gone far enough */
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
postend = offset + s->start + s->len;
if (postend <= cut) {
/* save this hunk */
offset += s->start + s->len - s->end;
*d++ = *s++;
}
else {
/* break up this hunk */
c = cut - offset;
if (s->end < c)
c = s->end;
l = cut - offset - s->start;
if (s->len < l)
l = s->len;
offset += s->start + l - c;
d->start = s->start;
d->end = c;
d->len = l;
d->data = s->data;
d++;
s->start = c;
s->len = s->len - l;
s->data = s->data + l;
mpm@selenic.com
Gotos are embarrassing.
r82 break;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }
}
dest->tail = d;
src->head = s;
return offset;
}
/* like gather, but with no output list */
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 static int discard(struct mpatch_flist *src, int cut, int offset)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 struct mpatch_frag *s = src->head;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 int postend, c, l;
while (s != src->tail) {
if (s->start + offset >= cut)
mpm@selenic.com
Gotos are embarrassing.
r82 break;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
postend = offset + s->start + s->len;
if (postend <= cut) {
offset += s->start + s->len - s->end;
s++;
}
else {
c = cut - offset;
if (s->end < c)
c = s->end;
l = cut - offset - s->start;
if (s->len < l)
l = s->len;
offset += s->start + l - c;
s->start = c;
s->len = s->len - l;
s->data = s->data + l;
mpm@selenic.com
Gotos are embarrassing.
r82 break;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }
}
src->head = s;
return offset;
}
/* combine hunk lists a and b, while adjusting b for offset changes in a/
this deletes a and b and returns the resultant list. */
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 static struct mpatch_flist *combine(struct mpatch_flist *a,
struct mpatch_flist *b)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 struct mpatch_flist *c = NULL;
struct mpatch_frag *bh, *ct;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 int offset = 0, post;
mpm@selenic.com
Add safety checking to mpatch
r128 if (a && b)
c = lalloc((lsize(a) + lsize(b)) * 2);
if (c) {
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
mpm@selenic.com
Add safety checking to mpatch
r128 for (bh = b->head; bh != b->tail; bh++) {
/* save old hunks */
offset = gather(c, a, bh->start, offset);
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
mpm@selenic.com
Add safety checking to mpatch
r128 /* discard replaced hunks */
post = discard(a, bh->end, offset);
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
mpm@selenic.com
Add safety checking to mpatch
r128 /* insert new hunk */
ct = c->tail;
ct->start = bh->start - offset;
ct->end = bh->end - post;
ct->len = bh->len;
ct->data = bh->data;
c->tail++;
offset = post;
}
/* hold on to tail from a */
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 memcpy(c->tail, a->head, sizeof(struct mpatch_frag) * lsize(a));
mpm@selenic.com
Add safety checking to mpatch
r128 c->tail += lsize(a);
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 mpatch_lfree(a);
mpatch_lfree(b);
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 return c;
}
/* decode a binary patch into a hunk list */
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 int mpatch_decode(const char *bin, ssize_t len, struct mpatch_flist **res)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 struct mpatch_flist *l;
struct mpatch_frag *lt;
Matt Mackall
mpatch: rewrite pointer overflow checks
r20167 int pos = 0;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
/* assume worst case size, we won't have many of these lists */
Matt Mackall
parsers: fix list sizing rounding error (SEC)...
r28656 l = lalloc(len / 12 + 1);
Benoit Boissinot
catch errors and throw exception with invalid binary patch data
r1722 if (!l)
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 return MPATCH_ERR_NO_MEM;
Benoit Boissinot
catch errors and throw exception with invalid binary patch data
r1722
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 lt = l->tail;
Matt Mackall
mpatch: rewrite pointer overflow checks
r20167 while (pos >= 0 && pos < len) {
lt->start = getbe32(bin + pos);
lt->end = getbe32(bin + pos + 4);
lt->len = getbe32(bin + pos + 8);
lt->data = bin + pos + 12;
pos += 12 + lt->len;
Matt Mackall
parsers: detect short records (SEC)...
r28657 if (lt->start > lt->end || lt->len < 0)
break; /* sanity check */
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 lt++;
}
Matt Mackall
mpatch: rewrite pointer overflow checks
r20167 if (pos != len) {
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 mpatch_lfree(l);
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 return MPATCH_ERR_CANNOT_BE_DECODED;
Benoit Boissinot
catch errors and throw exception with invalid binary patch data
r1722 }
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 l->tail = lt;
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 *res = l;
return 0;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }
/* calculate the size of resultant text */
Maciej Fijalkowski
mpatch: split mpatch into two files
r29693 ssize_t mpatch_calcsize(ssize_t len, struct mpatch_flist *l)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
Maciej Fijalkowski
mpatch: change Py_ssize_t to ssize_t in places that will be later copied
r29691 ssize_t outlen = 0, last = 0;
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 struct mpatch_frag *f = l->head;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
while (f != l->tail) {
Benoit Boissinot
catch errors and throw exception with invalid binary patch data
r1722 if (f->start < last || f->end > len) {
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 return MPATCH_ERR_INVALID_PATCH;
Benoit Boissinot
catch errors and throw exception with invalid binary patch data
r1722 }
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 outlen += f->start - last;
last = f->end;
outlen += f->len;
f++;
}
outlen += len - last;
return outlen;
}
Maciej Fijalkowski
mpatch: split mpatch into two files
r29693 int mpatch_apply(char *buf, const char *orig, ssize_t len,
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 struct mpatch_flist *l)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
Maciej Fijalkowski
mpatch: provide things that will be exported later with a prefixed name...
r29692 struct mpatch_frag *f = l->head;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 int last = 0;
char *p = buf;
while (f != l->tail) {
Benoit Boissinot
catch errors and throw exception with invalid binary patch data
r1722 if (f->start < last || f->end > len) {
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 return MPATCH_ERR_INVALID_PATCH;
Benoit Boissinot
catch errors and throw exception with invalid binary patch data
r1722 }
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 memcpy(p, orig + last, f->start - last);
p += f->start - last;
memcpy(p, f->data, f->len);
last = f->end;
p += f->len;
f++;
}
memcpy(p, orig + last, len - last);
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 return 0;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }
/* recursively generate a patch of all bins between start and end */
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 struct mpatch_flist *mpatch_fold(void *bins,
struct mpatch_flist* (*get_next_item)(void*, ssize_t),
ssize_t start, ssize_t end)
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 {
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 ssize_t len;
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72
if (start + 1 == end) {
/* trivial case, output a decoded list */
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 return get_next_item(bins, start);
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }
/* divide and conquer, memory management is elsewhere */
len = (end - start) / 2;
Maciej Fijalkowski
mpatch: remove dependency on Python.h in mpatch.c...
r29694 return combine(mpatch_fold(bins, get_next_item, start, start + len),
mpatch_fold(bins, get_next_item, start + len, end));
mpm@selenic.com
Add an O(m + nlog n) patching extension
r72 }