Show More
@@ -26,10 +26,89 b' def _string_escape(text):' | |||||
26 | def _string_unescape(text): |
|
26 | def _string_unescape(text): | |
27 | return text.decode('string_escape') |
|
27 | return text.decode('string_escape') | |
28 |
|
28 | |||
|
29 | class appender: | |||
|
30 | '''the changelog index must be update last on disk, so we use this class | |||
|
31 | to delay writes to it''' | |||
|
32 | def __init__(self, fp, buf): | |||
|
33 | self.data = buf | |||
|
34 | self.fp = fp | |||
|
35 | self.offset = fp.tell() | |||
|
36 | self.size = util.fstat(fp).st_size | |||
|
37 | ||||
|
38 | def end(self): | |||
|
39 | return self.size + len("".join(self.data)) | |||
|
40 | def tell(self): | |||
|
41 | return self.offset | |||
|
42 | def flush(self): | |||
|
43 | pass | |||
|
44 | def close(self): | |||
|
45 | close(self.fp) | |||
|
46 | ||||
|
47 | def seek(self, offset, whence=0): | |||
|
48 | '''virtual file offset spans real file and data''' | |||
|
49 | if whence == 0: | |||
|
50 | self.offset = offset | |||
|
51 | elif whence == 1: | |||
|
52 | self.offset += offset | |||
|
53 | elif whence == 2: | |||
|
54 | self.offset = self.end() + offset | |||
|
55 | if self.offset < self.size: | |||
|
56 | self.fp.seek(self.offset) | |||
|
57 | ||||
|
58 | def read(self, count=-1): | |||
|
59 | '''only trick here is reads that span real file and data''' | |||
|
60 | ret = "" | |||
|
61 | old_offset = self.offset | |||
|
62 | if self.offset < self.size: | |||
|
63 | s = self.fp.read(count) | |||
|
64 | ret = s | |||
|
65 | self.offset += len(s) | |||
|
66 | if count > 0: | |||
|
67 | count -= len(s) | |||
|
68 | if count != 0: | |||
|
69 | doff = self.offset - self.size | |||
|
70 | self.data.insert(0, "".join(self.data)) | |||
|
71 | del self.data[1:] | |||
|
72 | s = self.data[0][doff:doff+count] | |||
|
73 | self.offset += len(s) | |||
|
74 | ret += s | |||
|
75 | return ret | |||
|
76 | ||||
|
77 | def write(self, s): | |||
|
78 | self.data.append(s) | |||
|
79 | self.offset += len(s) | |||
|
80 | ||||
29 | class changelog(revlog): |
|
81 | class changelog(revlog): | |
30 | def __init__(self, opener): |
|
82 | def __init__(self, opener): | |
31 | revlog.__init__(self, opener, "00changelog.i") |
|
83 | revlog.__init__(self, opener, "00changelog.i") | |
32 |
|
84 | |||
|
85 | def delayupdate(self): | |||
|
86 | "delay visibility of index updates to other readers" | |||
|
87 | self._realopener = self.opener | |||
|
88 | self.opener = self._appendopener | |||
|
89 | self._delaybuf = [] | |||
|
90 | ||||
|
91 | def finalize(self, tr): | |||
|
92 | "finalize index updates" | |||
|
93 | self.opener = self._realopener | |||
|
94 | if self._delaybuf: | |||
|
95 | fp = self.opener(self.indexfile, 'a') | |||
|
96 | fp.write("".join(self._delaybuf)) | |||
|
97 | fp.close() | |||
|
98 | del self._delaybuf | |||
|
99 | self.checkinlinesize(tr) | |||
|
100 | ||||
|
101 | def _appendopener(self, name, mode='r'): | |||
|
102 | fp = self._realopener(name, mode) | |||
|
103 | if not name == self.indexfile: | |||
|
104 | return fp | |||
|
105 | return appender(fp, self._delaybuf) | |||
|
106 | ||||
|
107 | def checkinlinesize(self, tr, fp=None): | |||
|
108 | if self.opener == self._appendopener: | |||
|
109 | return | |||
|
110 | return revlog.checkinlinesize(self, tr, fp) | |||
|
111 | ||||
33 | def decode_extra(self, text): |
|
112 | def decode_extra(self, text): | |
34 | extra = {} |
|
113 | extra = {} | |
35 | for l in text.split('\0'): |
|
114 | for l in text.split('\0'): |
@@ -7,7 +7,7 b'' | |||||
7 |
|
7 | |||
8 | from node import * |
|
8 | from node import * | |
9 | from i18n import _ |
|
9 | from i18n import _ | |
10 |
import repo, |
|
10 | import repo, changegroup | |
11 | import changelog, dirstate, filelog, manifest, context |
|
11 | import changelog, dirstate, filelog, manifest, context | |
12 | import re, lock, transaction, tempfile, stat, mdiff, errno, ui |
|
12 | import re, lock, transaction, tempfile, stat, mdiff, errno, ui | |
13 | import os, revlog, time, util |
|
13 | import os, revlog, time, util | |
@@ -1782,52 +1782,45 b' class localrepository(repo.repository):' | |||||
1782 |
|
1782 | |||
1783 | # write changelog data to temp files so concurrent readers will not see |
|
1783 | # write changelog data to temp files so concurrent readers will not see | |
1784 | # inconsistent view |
|
1784 | # inconsistent view | |
1785 |
cl = |
|
1785 | cl = self.changelog | |
1786 | try: |
|
1786 | cl.delayupdate() | |
1787 | cl = appendfile.appendchangelog(self.sopener) |
|
1787 | oldheads = len(cl.heads()) | |
1788 | oldheads = len(cl.heads()) |
|
1788 | ||
|
1789 | # pull off the changeset group | |||
|
1790 | self.ui.status(_("adding changesets\n")) | |||
|
1791 | cor = cl.count() - 1 | |||
|
1792 | chunkiter = changegroup.chunkiter(source) | |||
|
1793 | if cl.addgroup(chunkiter, csmap, tr, 1) is None: | |||
|
1794 | raise util.Abort(_("received changelog group is empty")) | |||
|
1795 | cnr = cl.count() - 1 | |||
|
1796 | changesets = cnr - cor | |||
1789 |
|
1797 | |||
1790 |
|
|
1798 | # pull off the manifest group | |
1791 |
|
|
1799 | self.ui.status(_("adding manifests\n")) | |
1792 | cor = cl.count() - 1 |
|
1800 | chunkiter = changegroup.chunkiter(source) | |
1793 | chunkiter = changegroup.chunkiter(source) |
|
1801 | # no need to check for empty manifest group here: | |
1794 | if cl.addgroup(chunkiter, csmap, tr, 1) is None: |
|
1802 | # if the result of the merge of 1 and 2 is the same in 3 and 4, | |
1795 | raise util.Abort(_("received changelog group is empty")) |
|
1803 | # no new manifest will be created and the manifest group will | |
1796 | cnr = cl.count() - 1 |
|
1804 | # be empty during the pull | |
1797 | changesets = cnr - cor |
|
1805 | self.manifest.addgroup(chunkiter, revmap, tr) | |
1798 |
|
1806 | |||
1799 | # pull off the manifest group |
|
1807 | # process the files | |
1800 |
|
|
1808 | self.ui.status(_("adding file changes\n")) | |
|
1809 | while 1: | |||
|
1810 | f = changegroup.getchunk(source) | |||
|
1811 | if not f: | |||
|
1812 | break | |||
|
1813 | self.ui.debug(_("adding %s revisions\n") % f) | |||
|
1814 | fl = self.file(f) | |||
|
1815 | o = fl.count() | |||
1801 | chunkiter = changegroup.chunkiter(source) |
|
1816 | chunkiter = changegroup.chunkiter(source) | |
1802 | # no need to check for empty manifest group here: |
|
1817 | if fl.addgroup(chunkiter, revmap, tr) is None: | |
1803 | # if the result of the merge of 1 and 2 is the same in 3 and 4, |
|
1818 | raise util.Abort(_("received file revlog group is empty")) | |
1804 | # no new manifest will be created and the manifest group will |
|
1819 | revisions += fl.count() - o | |
1805 | # be empty during the pull |
|
1820 | files += 1 | |
1806 | self.manifest.addgroup(chunkiter, revmap, tr) |
|
|||
1807 |
|
||||
1808 | # process the files |
|
|||
1809 | self.ui.status(_("adding file changes\n")) |
|
|||
1810 | while 1: |
|
|||
1811 | f = changegroup.getchunk(source) |
|
|||
1812 | if not f: |
|
|||
1813 | break |
|
|||
1814 | self.ui.debug(_("adding %s revisions\n") % f) |
|
|||
1815 | fl = self.file(f) |
|
|||
1816 | o = fl.count() |
|
|||
1817 | chunkiter = changegroup.chunkiter(source) |
|
|||
1818 | if fl.addgroup(chunkiter, revmap, tr) is None: |
|
|||
1819 | raise util.Abort(_("received file revlog group is empty")) |
|
|||
1820 | revisions += fl.count() - o |
|
|||
1821 | files += 1 |
|
|||
1822 |
|
||||
1823 | cl.writedata() |
|
|||
1824 | finally: |
|
|||
1825 | if cl: |
|
|||
1826 | cl.cleanup() |
|
|||
1827 |
|
1821 | |||
1828 | # make changelog see real files again |
|
1822 | # make changelog see real files again | |
1829 | self.changelog = changelog.changelog(self.sopener) |
|
1823 | cl.finalize(tr) | |
1830 | self.changelog.checkinlinesize(tr) |
|
|||
1831 |
|
1824 | |||
1832 | newheads = len(self.changelog.heads()) |
|
1825 | newheads = len(self.changelog.heads()) | |
1833 | heads = "" |
|
1826 | heads = "" |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now