~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/statcache.py

  • Committer: Martin Pool
  • Date: 2005-05-16 04:32:21 UTC
  • Revision ID: mbp@sourcefrog.net-20050516043221-12a9da66feb5d67b
clean up stat cache code:
- smarter UTF-8 and quopri encoding of file names
- check paths are not duplicated in cache
- check lines are well-formed
- more docs

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
from binascii import b2a_qp, a2b_qp
19
19
 
20
20
from trace import mutter
21
 
from errors import BzrError
 
21
from errors import BzrError, BzrCheckError
22
22
 
23
23
 
24
24
"""File stat cache to speed up tree comparisons.
27
27
information of a file in the working directory, without actually
28
28
reading and hashing the whole file.
29
29
 
 
30
 
 
31
 
 
32
Implementation
 
33
==============
 
34
 
 
35
Users of this module should not need to know about how this is
 
36
implemented, and in particular should not depend on the particular
 
37
data which is stored or its format.
 
38
 
30
39
This is done by maintaining a cache indexed by a file fingerprint of
31
40
(path, size, mtime, ctime, ino, dev) pointing to the SHA-1.  If the
32
41
fingerprint has changed, we assume the file content has not changed
54
63
 
55
64
The cache is represented as a map from file_id to a tuple of (file_id,
56
65
sha1, path, size, mtime, ctime, ino, dev).
 
66
 
 
67
The SHA-1 is stored in memory as a hexdigest.
 
68
 
 
69
File names are written out as the quoted-printable encoding of their
 
70
UTF-8 representation.
57
71
"""
58
72
 
59
 
 
 
73
# order of fields returned by fingerprint()
60
74
FP_SIZE  = 0
61
75
FP_MTIME = 1
62
76
FP_CTIME = 2
63
77
FP_INO   = 3
64
78
FP_DEV   = 4
65
79
 
66
 
 
 
80
# order of fields in the statcache file and in the in-memory map
67
81
SC_FILE_ID = 0
68
 
SC_SHA1    = 1 
 
82
SC_SHA1    = 1
 
83
SC_PATH    = 2
 
84
SC_SIZE    = 3
 
85
SC_MTIME   = 4
 
86
SC_CTIME   = 5
 
87
SC_INO     = 6
 
88
SC_DEV     = 7
69
89
 
70
90
 
71
91
def fingerprint(abspath):
86
106
    from atomicfile import AtomicFile
87
107
 
88
108
    cachefn = os.path.join(basedir, '.bzr', 'stat-cache')
89
 
    outf = AtomicFile(cachefn, 'wb', 'utf-8')
 
109
    outf = AtomicFile(cachefn, 'wb')
90
110
    try:
91
111
        for entry in entry_iter:
92
 
            if entry[0] in dangerfiles:
93
 
                continue
94
 
            outf.write(entry[0] + ' ' + entry[1] + ' ')
95
 
            outf.write(b2a_qp(entry[2], True))
96
 
            outf.write(' %d %d %d %d %d\n' % entry[3:])
 
112
            if len(entry) != 8:
 
113
                raise ValueError("invalid statcache entry tuple %r" % entry)
 
114
            
 
115
            if entry[SC_FILE_ID] in dangerfiles:
 
116
                continue                # changed too recently
 
117
            outf.write(entry[0])        # file id
 
118
            outf.write(' ')
 
119
            outf.write(entry[1])        # hex sha1
 
120
            outf.write(' ')
 
121
            outf.write(b2a_qp(entry[2].encode('utf-8'), True)) # name
 
122
            for nf in entry[3:]:
 
123
                outf.write(' %d' % nf)
 
124
            outf.write('\n')
97
125
 
98
126
        outf.commit()
99
127
    finally:
102
130
        
103
131
        
104
132
def load_cache(basedir):
105
 
    import codecs
106
 
    
 
133
    from sets import Set
107
134
    cache = {}
 
135
    seen_paths = Set()
108
136
 
109
137
    try:
110
138
        cachefn = os.path.join(basedir, '.bzr', 'stat-cache')
111
 
        cachefile = codecs.open(cachefn, 'r', 'utf-8')
 
139
        cachefile = open(cachefn, 'r')
112
140
    except IOError:
113
141
        return cache
114
142
    
115
143
    for l in cachefile:
116
144
        f = l.split(' ')
 
145
 
117
146
        file_id = f[0]
118
147
        if file_id in cache:
119
148
            raise BzrError("duplicated file_id in cache: {%s}" % file_id)
120
 
        cache[file_id] = (f[0], f[1], a2b_qp(f[2])) + tuple([long(x) for x in f[3:]])
 
149
        
 
150
        path = a2b_qp(f[2]).decode('utf-8')
 
151
        if path in seen_paths:
 
152
            raise BzrCheckError("duplicated path in cache: %r" % path)
 
153
        seen_paths.add(path)
 
154
        
 
155
        entry = (file_id, f[1], path) + tuple([long(x) for x in f[3:]])
 
156
        if len(entry) != 8:
 
157
            raise ValueError("invalid statcache entry tuple %r" % entry)
 
158
 
 
159
        cache[file_id] = entry
121
160
    return cache
122
161
 
123
162