Show More
@@ -786,23 +786,26 b' class filecacheentry(object):' | |||||
786 | entry.refresh() |
|
786 | entry.refresh() | |
787 |
|
787 | |||
788 | class filecache(object): |
|
788 | class filecache(object): | |
789 |
'''A property like decorator that tracks |
|
789 | '''A property like decorator that tracks files under .hg/ for updates. | |
790 |
|
790 | |||
791 | Records stat info when called in _filecache. |
|
791 | Records stat info when called in _filecache. | |
792 |
|
792 | |||
793 | On subsequent calls, compares old stat info with new info, and recreates |
|
793 | On subsequent calls, compares old stat info with new info, and recreates the | |
794 |
|
|
794 | object when any of the files changes, updating the new stat info in | |
|
795 | _filecache. | |||
795 |
|
796 | |||
796 | Mercurial either atomic renames or appends for files under .hg, |
|
797 | Mercurial either atomic renames or appends for files under .hg, | |
797 | so to ensure the cache is reliable we need the filesystem to be able |
|
798 | so to ensure the cache is reliable we need the filesystem to be able | |
798 | to tell us if a file has been replaced. If it can't, we fallback to |
|
799 | to tell us if a file has been replaced. If it can't, we fallback to | |
799 | recreating the object on every call (essentially the same behaviour as |
|
800 | recreating the object on every call (essentially the same behaviour as | |
800 |
propertycache). |
|
801 | propertycache). | |
801 | def __init__(self, path): |
|
802 | ||
802 | self.path = path |
|
803 | ''' | |
|
804 | def __init__(self, *paths): | |||
|
805 | self.paths = paths | |||
803 |
|
806 | |||
804 | def join(self, obj, fname): |
|
807 | def join(self, obj, fname): | |
805 |
"""Used to compute the runtime path of |
|
808 | """Used to compute the runtime path of a cached file. | |
806 |
|
809 | |||
807 | Users should subclass filecache and provide their own version of this |
|
810 | Users should subclass filecache and provide their own version of this | |
808 | function to call the appropriate join function on 'obj' (an instance |
|
811 | function to call the appropriate join function on 'obj' (an instance | |
@@ -827,11 +830,11 b' class filecache(object):' | |||||
827 | if entry.changed(): |
|
830 | if entry.changed(): | |
828 | entry.obj = self.func(obj) |
|
831 | entry.obj = self.func(obj) | |
829 | else: |
|
832 | else: | |
830 |
path = self.join(obj, self.path |
|
833 | paths = [self.join(obj, path) for path in self.paths] | |
831 |
|
834 | |||
832 | # We stat -before- creating the object so our cache doesn't lie if |
|
835 | # We stat -before- creating the object so our cache doesn't lie if | |
833 | # a writer modified between the time we read and stat |
|
836 | # a writer modified between the time we read and stat | |
834 |
entry = filecache |
|
837 | entry = filecacheentry(paths, True) | |
835 | entry.obj = self.func(obj) |
|
838 | entry.obj = self.func(obj) | |
836 |
|
839 | |||
837 | obj._filecache[self.name] = entry |
|
840 | obj._filecache[self.name] = entry | |
@@ -843,7 +846,8 b' class filecache(object):' | |||||
843 | if self.name not in obj._filecache: |
|
846 | if self.name not in obj._filecache: | |
844 | # we add an entry for the missing value because X in __dict__ |
|
847 | # we add an entry for the missing value because X in __dict__ | |
845 | # implies X in _filecache |
|
848 | # implies X in _filecache | |
846 |
|
|
849 | paths = [self.join(obj, path) for path in self.paths] | |
|
850 | ce = filecacheentry(paths, False) | |||
847 | obj._filecache[self.name] = ce |
|
851 | obj._filecache[self.name] = ce | |
848 | else: |
|
852 | else: | |
849 | ce = obj._filecache[self.name] |
|
853 | ce = obj._filecache[self.name] |
@@ -18,7 +18,7 b' class fakerepo(object):' | |||||
18 | def sjoin(self, p): |
|
18 | def sjoin(self, p): | |
19 | return p |
|
19 | return p | |
20 |
|
20 | |||
21 | @filecache('x') |
|
21 | @filecache('x', 'y') | |
22 | def cached(self): |
|
22 | def cached(self): | |
23 | print 'creating' |
|
23 | print 'creating' | |
24 | return 'string from function' |
|
24 | return 'string from function' | |
@@ -31,12 +31,12 b' class fakerepo(object):' | |||||
31 | pass |
|
31 | pass | |
32 |
|
32 | |||
33 | def basic(repo): |
|
33 | def basic(repo): | |
34 |
print "* file |
|
34 | print "* neither file exists" | |
35 | # calls function |
|
35 | # calls function | |
36 | repo.cached |
|
36 | repo.cached | |
37 |
|
37 | |||
38 | repo.invalidate() |
|
38 | repo.invalidate() | |
39 |
print "* file still |
|
39 | print "* neither file still exists" | |
40 | # uses cache |
|
40 | # uses cache | |
41 | repo.cached |
|
41 | repo.cached | |
42 |
|
42 | |||
@@ -57,7 +57,7 b' def basic(repo):' | |||||
57 | repo.cached |
|
57 | repo.cached | |
58 |
|
58 | |||
59 | repo.invalidate() |
|
59 | repo.invalidate() | |
60 |
print "* nothing changed with file |
|
60 | print "* nothing changed with either file" | |
61 | # stats file again, reuses object |
|
61 | # stats file again, reuses object | |
62 | repo.cached |
|
62 | repo.cached | |
63 |
|
63 | |||
@@ -72,6 +72,41 b' def basic(repo):' | |||||
72 | print "* file x changed inode" |
|
72 | print "* file x changed inode" | |
73 | repo.cached |
|
73 | repo.cached | |
74 |
|
74 | |||
|
75 | # create empty file y | |||
|
76 | f = open('y', 'w') | |||
|
77 | f.close() | |||
|
78 | repo.invalidate() | |||
|
79 | print "* empty file y created" | |||
|
80 | # should recreate the object | |||
|
81 | repo.cached | |||
|
82 | ||||
|
83 | f = open('y', 'w') | |||
|
84 | f.write('A') | |||
|
85 | f.close() | |||
|
86 | repo.invalidate() | |||
|
87 | print "* file y changed size" | |||
|
88 | # should recreate the object | |||
|
89 | repo.cached | |||
|
90 | ||||
|
91 | f = scmutil.opener('.')('y', 'w', atomictemp=True) | |||
|
92 | f.write('B') | |||
|
93 | f.close() | |||
|
94 | ||||
|
95 | repo.invalidate() | |||
|
96 | print "* file y changed inode" | |||
|
97 | repo.cached | |||
|
98 | ||||
|
99 | f = scmutil.opener('.')('x', 'w', atomictemp=True) | |||
|
100 | f.write('c') | |||
|
101 | f.close() | |||
|
102 | f = scmutil.opener('.')('y', 'w', atomictemp=True) | |||
|
103 | f.write('C') | |||
|
104 | f.close() | |||
|
105 | ||||
|
106 | repo.invalidate() | |||
|
107 | print "* both files changed inode" | |||
|
108 | repo.cached | |||
|
109 | ||||
75 | def fakeuncacheable(): |
|
110 | def fakeuncacheable(): | |
76 | def wrapcacheable(orig, *args, **kwargs): |
|
111 | def wrapcacheable(orig, *args, **kwargs): | |
77 | return False |
|
112 | return False | |
@@ -83,8 +118,9 b' def fakeuncacheable():' | |||||
83 | origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable', |
|
118 | origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable', | |
84 | wrapcacheable) |
|
119 | wrapcacheable) | |
85 |
|
120 | |||
|
121 | for fn in ['x', 'y']: | |||
86 | try: |
|
122 | try: | |
87 |
os.remove( |
|
123 | os.remove(fn) | |
88 | except OSError: |
|
124 | except OSError: | |
89 | pass |
|
125 | pass | |
90 |
|
126 | |||
@@ -110,9 +146,10 b' def test_filecache_synced():' | |||||
110 |
|
146 | |||
111 | def setbeforeget(repo): |
|
147 | def setbeforeget(repo): | |
112 | os.remove('x') |
|
148 | os.remove('x') | |
|
149 | os.remove('y') | |||
113 | repo.cached = 'string set externally' |
|
150 | repo.cached = 'string set externally' | |
114 | repo.invalidate() |
|
151 | repo.invalidate() | |
115 |
print "* file |
|
152 | print "* neither file exists" | |
116 | print repo.cached |
|
153 | print repo.cached | |
117 | repo.invalidate() |
|
154 | repo.invalidate() | |
118 | f = open('x', 'w') |
|
155 | f = open('x', 'w') | |
@@ -121,6 +158,18 b' def setbeforeget(repo):' | |||||
121 | print "* file x created" |
|
158 | print "* file x created" | |
122 | print repo.cached |
|
159 | print repo.cached | |
123 |
|
160 | |||
|
161 | repo.cached = 'string 2 set externally' | |||
|
162 | repo.invalidate() | |||
|
163 | print "* string set externally again" | |||
|
164 | print repo.cached | |||
|
165 | ||||
|
166 | repo.invalidate() | |||
|
167 | f = open('y', 'w') | |||
|
168 | f.write('b') | |||
|
169 | f.close() | |||
|
170 | print "* file y created" | |||
|
171 | print repo.cached | |||
|
172 | ||||
124 | print 'basic:' |
|
173 | print 'basic:' | |
125 |
|
174 | |||
126 | basic(fakerepo()) |
|
175 | basic(fakerepo()) |
@@ -1,30 +1,46 b'' | |||||
1 | basic: |
|
1 | basic: | |
2 |
|
2 | |||
3 | * file doesn't exist |
|
3 | * neither file exists | |
4 | creating |
|
4 | creating | |
5 |
* file still |
|
5 | * neither file still exists | |
6 | * empty file x created |
|
6 | * empty file x created | |
7 | creating |
|
7 | creating | |
8 | * file x changed size |
|
8 | * file x changed size | |
9 | creating |
|
9 | creating | |
10 |
* nothing changed with file |
|
10 | * nothing changed with either file | |
11 | * file x changed inode |
|
11 | * file x changed inode | |
12 | creating |
|
12 | creating | |
|
13 | * empty file y created | |||
|
14 | creating | |||
|
15 | * file y changed size | |||
|
16 | creating | |||
|
17 | * file y changed inode | |||
|
18 | creating | |||
|
19 | * both files changed inode | |||
|
20 | creating | |||
13 |
|
21 | |||
14 | fakeuncacheable: |
|
22 | fakeuncacheable: | |
15 |
|
23 | |||
16 | * file doesn't exist |
|
24 | * neither file exists | |
17 | creating |
|
25 | creating | |
18 |
* file still |
|
26 | * neither file still exists | |
19 | creating |
|
27 | creating | |
20 | * empty file x created |
|
28 | * empty file x created | |
21 | creating |
|
29 | creating | |
22 | * file x changed size |
|
30 | * file x changed size | |
23 | creating |
|
31 | creating | |
24 |
* nothing changed with file |
|
32 | * nothing changed with either file | |
25 | creating |
|
33 | creating | |
26 | * file x changed inode |
|
34 | * file x changed inode | |
27 | creating |
|
35 | creating | |
|
36 | * empty file y created | |||
|
37 | creating | |||
|
38 | * file y changed size | |||
|
39 | creating | |||
|
40 | * file y changed inode | |||
|
41 | creating | |||
|
42 | * both files changed inode | |||
|
43 | creating | |||
28 | repository tip rolled back to revision -1 (undo commit) |
|
44 | repository tip rolled back to revision -1 (undo commit) | |
29 | working directory now based on revision -1 |
|
45 | working directory now based on revision -1 | |
30 | repository tip rolled back to revision -1 (undo commit) |
|
46 | repository tip rolled back to revision -1 (undo commit) | |
@@ -32,8 +48,13 b' working directory now based on revision ' | |||||
32 |
|
48 | |||
33 | setbeforeget: |
|
49 | setbeforeget: | |
34 |
|
50 | |||
35 | * file x doesn't exist |
|
51 | * neither file exists | |
36 | string set externally |
|
52 | string set externally | |
37 | * file x created |
|
53 | * file x created | |
38 | creating |
|
54 | creating | |
39 | string from function |
|
55 | string from function | |
|
56 | * string set externally again | |||
|
57 | string 2 set externally | |||
|
58 | * file y created | |||
|
59 | creating | |||
|
60 | string from function |
General Comments 0
You need to be logged in to leave comments.
Login now