##// END OF EJS Templates
scmutil.filecache: support watching over multiple files
Siddharth Agarwal -
r20045:b3684fd2 default
parent child Browse files
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 a file under .hg/ for updates.
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 the object when needed, updating the new stat info in _filecache.
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 the cached file.
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 = filecachesubentry(path, True)
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 ce = filecachesubentry(self.join(obj, self.path), False)
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 doesn't exist"
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 doesn't exist"
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 x"
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,10 +118,11 b' def fakeuncacheable():'
83 origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable',
118 origcacheable = extensions.wrapfunction(util.cachestat, 'cacheable',
84 wrapcacheable)
119 wrapcacheable)
85
120
86 try:
121 for fn in ['x', 'y']:
87 os.remove('x')
122 try:
88 except OSError:
123 os.remove(fn)
89 pass
124 except OSError:
125 pass
90
126
91 basic(fakerepo())
127 basic(fakerepo())
92
128
@@ -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 x doesn't exist"
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 print
174 print
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 doesn't exist
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 x
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 doesn't exist
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 x
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