~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/dirstate.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-03-06 06:48:25 UTC
  • mfrom: (4070.8.6 debug-config)
  • Revision ID: pqm@pqm.ubuntu.com-20090306064825-kbpwggw21dygeix6
(mbp) debug_flags configuration option

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""DirState objects record the state of a directory and its bzr metadata.
18
18
 
82
82
'a' is an absent entry: In that tree the id is not present at this path.
83
83
'd' is a directory entry: This path in this tree is a directory with the
84
84
    current file id. There is no fingerprint for directories.
85
 
'f' is a file entry: As for directory, but it's a file. The fingerprint is the
86
 
    sha1 value of the file's canonical form, i.e. after any read filters have
87
 
    been applied to the convenience form stored in the working tree.
 
85
'f' is a file entry: As for directory, but its a file. The fingerprint is a
 
86
    sha1 value.
88
87
'l' is a symlink entry: As for directory, but a symlink. The fingerprint is the
89
88
    link target.
90
89
't' is a reference to a nested subtree; the fingerprint is the referenced
187
186
the file on disk, and then immediately discard, the overhead of object creation
188
187
becomes a significant cost.
189
188
 
190
 
Figures: Creating a tuple from 3 elements was profiled at 0.0625
 
189
Figures: Creating a tuple from from 3 elements was profiled at 0.0625
191
190
microseconds, whereas creating a object which is subclassed from tuple was
192
191
0.500 microseconds, and creating an object with 3 elements and slots was 3
193
192
microseconds long. 0.1 milliseconds is 100 microseconds, and ideally we'll get
263
262
        # return '%X.%X' % (int(st.st_mtime), st.st_mode)
264
263
 
265
264
 
266
 
class SHA1Provider(object):
267
 
    """An interface for getting sha1s of a file."""
268
 
 
269
 
    def sha1(self, abspath):
270
 
        """Return the sha1 of a file given its absolute path."""
271
 
        raise NotImplementedError(self.sha1)
272
 
 
273
 
    def stat_and_sha1(self, abspath):
274
 
        """Return the stat and sha1 of a file given its absolute path.
275
 
        
276
 
        Note: the stat should be the stat of the physical file
277
 
        while the sha may be the sha of its canonical content.
278
 
        """
279
 
        raise NotImplementedError(self.stat_and_sha1)
280
 
 
281
 
 
282
 
class DefaultSHA1Provider(SHA1Provider):
283
 
    """A SHA1Provider that reads directly from the filesystem."""
284
 
 
285
 
    def sha1(self, abspath):
286
 
        """Return the sha1 of a file given its absolute path."""
287
 
        return osutils.sha_file_by_name(abspath)
288
 
 
289
 
    def stat_and_sha1(self, abspath):
290
 
        """Return the stat and sha1 of a file given its absolute path."""
291
 
        file_obj = file(abspath, 'rb')
292
 
        try:
293
 
            statvalue = os.fstat(file_obj.fileno())
294
 
            sha1 = osutils.sha_file(file_obj)
295
 
        finally:
296
 
            file_obj.close()
297
 
        return statvalue, sha1
298
 
 
299
 
 
300
265
class DirState(object):
301
266
    """Record directory and metadata state for fast access.
302
267
 
355
320
    HEADER_FORMAT_2 = '#bazaar dirstate flat format 2\n'
356
321
    HEADER_FORMAT_3 = '#bazaar dirstate flat format 3\n'
357
322
 
358
 
    def __init__(self, path, sha1_provider):
 
323
    def __init__(self, path):
359
324
        """Create a  DirState object.
360
325
 
361
326
        :param path: The path at which the dirstate file on disk should live.
362
 
        :param sha1_provider: an object meeting the SHA1Provider interface.
363
327
        """
364
328
        # _header_state and _dirblock_state represent the current state
365
329
        # of the dirstate metadata and the per-row data respectiely.
391
355
        self._cutoff_time = None
392
356
        self._split_path_cache = {}
393
357
        self._bisect_page_size = DirState.BISECT_PAGE_SIZE
394
 
        self._sha1_provider = sha1_provider
395
358
        if 'hashcache' in debug.debug_flags:
396
359
            self._sha1_file = self._sha1_file_and_mutter
397
360
        else:
398
 
            self._sha1_file = self._sha1_provider.sha1
 
361
            self._sha1_file = osutils.sha_file_by_name
399
362
        # These two attributes provide a simple cache for lookups into the
400
363
        # dirstate in-memory vectors. By probing respectively for the last
401
364
        # block, and for the next entry, we save nearly 2 bisections per path
417
380
        :param kind: The kind of the path, as a string like 'file',
418
381
            'directory', etc.
419
382
        :param stat: The output of os.lstat for the path.
420
 
        :param fingerprint: The sha value of the file's canonical form (i.e.
421
 
            after any read filters have been applied),
 
383
        :param fingerprint: The sha value of the file,
422
384
            or the target of a symlink,
423
385
            or the referenced revision id for tree-references,
424
386
            or '' for directories.
1232
1194
        return entry_index, present
1233
1195
 
1234
1196
    @staticmethod
1235
 
    def from_tree(tree, dir_state_filename, sha1_provider=None):
 
1197
    def from_tree(tree, dir_state_filename):
1236
1198
        """Create a dirstate from a bzr Tree.
1237
1199
 
1238
1200
        :param tree: The tree which should provide parent information and
1239
1201
            inventory ids.
1240
 
        :param sha1_provider: an object meeting the SHA1Provider interface.
1241
 
            If None, a DefaultSHA1Provider is used.
1242
1202
        :return: a DirState object which is currently locked for writing.
1243
1203
            (it was locked by DirState.initialize)
1244
1204
        """
1245
 
        result = DirState.initialize(dir_state_filename,
1246
 
            sha1_provider=sha1_provider)
 
1205
        result = DirState.initialize(dir_state_filename)
1247
1206
        try:
1248
1207
            tree.lock_read()
1249
1208
            try:
1610
1569
        # when -Dhashcache is turned on, this is monkey-patched in to log
1611
1570
        # file reads
1612
1571
        trace.mutter("dirstate sha1 " + abspath)
1613
 
        return self._sha1_provider.sha1(abspath)
 
1572
        return osutils.sha_file_by_name(abspath)
1614
1573
 
1615
1574
    def _is_executable(self, mode, old_executable):
1616
1575
        """Is this file executable?"""
1629
1588
        #       already in memory. However, this really needs to be done at a
1630
1589
        #       higher level, because there either won't be anything on disk,
1631
1590
        #       or the thing on disk will be a file.
1632
 
        fs_encoding = osutils._fs_enc
1633
 
        if isinstance(abspath, unicode):
1634
 
            # abspath is defined as the path to pass to lstat. readlink is
1635
 
            # buggy in python < 2.6 (it doesn't encode unicode path into FS
1636
 
            # encoding), so we need to encode ourselves knowing that unicode
1637
 
            # paths are produced by UnicodeDirReader on purpose.
1638
 
            abspath = abspath.encode(fs_encoding)
1639
 
        target = os.readlink(abspath)
1640
 
        if fs_encoding not in ('UTF-8', 'US-ASCII', 'ANSI_X3.4-1968'):
1641
 
            # Change encoding if needed
1642
 
            target = target.decode(fs_encoding).encode('UTF-8')
1643
 
        return target
 
1591
        return os.readlink(abspath.encode(osutils._fs_enc))
1644
1592
 
1645
1593
    def get_ghosts(self):
1646
1594
        """Return a list of the parent tree revision ids that are ghosts."""
1870
1818
            return None, None
1871
1819
 
1872
1820
    @classmethod
1873
 
    def initialize(cls, path, sha1_provider=None):
 
1821
    def initialize(cls, path):
1874
1822
        """Create a new dirstate on path.
1875
1823
 
1876
1824
        The new dirstate will be an empty tree - that is it has no parents,
1877
1825
        and only a root node - which has id ROOT_ID.
1878
1826
 
1879
1827
        :param path: The name of the file for the dirstate.
1880
 
        :param sha1_provider: an object meeting the SHA1Provider interface.
1881
 
            If None, a DefaultSHA1Provider is used.
1882
1828
        :return: A write-locked DirState object.
1883
1829
        """
1884
1830
        # This constructs a new DirState object on a path, sets the _state_file
1886
1832
        # stock empty dirstate information - a root with ROOT_ID, no children,
1887
1833
        # and no parents. Finally it calls save() to ensure that this data will
1888
1834
        # persist.
1889
 
        if sha1_provider is None:
1890
 
            sha1_provider = DefaultSHA1Provider()
1891
 
        result = cls(path, sha1_provider)
 
1835
        result = cls(path)
1892
1836
        # root dir and root dir contents with no children.
1893
1837
        empty_tree_dirblocks = [('', []), ('', [])]
1894
1838
        # a new root directory, with a NULLSTAT.
1922
1866
            size = 0
1923
1867
            executable = False
1924
1868
        elif kind == 'symlink':
1925
 
            if inv_entry.symlink_target is None:
1926
 
                fingerprint = ''
1927
 
            else:
1928
 
                fingerprint = inv_entry.symlink_target.encode('utf8')
 
1869
            # We don't support non-ascii targets for symlinks yet.
 
1870
            fingerprint = str(inv_entry.symlink_target or '')
1929
1871
            size = 0
1930
1872
            executable = False
1931
1873
        elif kind == 'file':
2027
1969
        return len(self._parents) - len(self._ghosts)
2028
1970
 
2029
1971
    @staticmethod
2030
 
    def on_file(path, sha1_provider=None):
2031
 
        """Construct a DirState on the file at path "path".
 
1972
    def on_file(path):
 
1973
        """Construct a DirState on the file at path path.
2032
1974
 
2033
 
        :param path: The path at which the dirstate file on disk should live.
2034
 
        :param sha1_provider: an object meeting the SHA1Provider interface.
2035
 
            If None, a DefaultSHA1Provider is used.
2036
1975
        :return: An unlocked DirState object, associated with the given path.
2037
1976
        """
2038
 
        if sha1_provider is None:
2039
 
            sha1_provider = DefaultSHA1Provider()
2040
 
        result = DirState(path, sha1_provider)
 
1977
        result = DirState(path)
2041
1978
        return result
2042
1979
 
2043
1980
    def _read_dirblocks_if_needed(self):
2532
2469
        :param minikind: The type for the entry ('f' == 'file', 'd' ==
2533
2470
                'directory'), etc.
2534
2471
        :param executable: Should the executable bit be set?
2535
 
        :param fingerprint: Simple fingerprint for new entry: canonical-form
2536
 
            sha1 for files, referenced revision id for subtrees, etc.
 
2472
        :param fingerprint: Simple fingerprint for new entry: sha1 for files,
 
2473
            referenced revision id for subtrees, etc.
2537
2474
        :param packed_stat: Packed stat value for new entry.
2538
2475
        :param size: Size information for new entry
2539
2476
        :param path_utf8: key[0] + '/' + key[1], just passed in to avoid doing
2870
2807
    (saved_minikind, saved_link_or_sha1, saved_file_size,
2871
2808
     saved_executable, saved_packed_stat) = entry[1][0]
2872
2809
 
2873
 
    if minikind == 'd' and saved_minikind == 't':
2874
 
        minikind = 't'
2875
2810
    if (minikind == saved_minikind
2876
2811
        and packed_stat == saved_packed_stat):
2877
2812
        # The stat hasn't changed since we saved, so we can re-use the
2895
2830
            and stat_value.st_ctime < state._cutoff_time
2896
2831
            and len(entry[1]) > 1
2897
2832
            and entry[1][1][0] != 'a'):
2898
 
            # Could check for size changes for further optimised
2899
 
            # avoidance of sha1's. However the most prominent case of
2900
 
            # over-shaing is during initial add, which this catches.
2901
 
            # Besides, if content filtering happens, size and sha
2902
 
            # are calculated at the same time, so checking just the size
2903
 
            # gains nothing w.r.t. performance.
 
2833
                # Could check for size changes for further optimised
 
2834
                # avoidance of sha1's. However the most prominent case of
 
2835
                # over-shaing is during initial add, which this catches.
2904
2836
            link_or_sha1 = state._sha1_file(abspath)
2905
2837
            entry[1][0] = ('f', link_or_sha1, stat_value.st_size,
2906
2838
                           executable, packed_stat)
3059
2991
                        if target_details[2] == source_details[2]:
3060
2992
                            if link_or_sha1 is None:
3061
2993
                                # Stat cache miss:
3062
 
                                statvalue, link_or_sha1 = \
3063
 
                                    self.state._sha1_provider.stat_and_sha1(
3064
 
                                    path_info[4])
 
2994
                                file_obj = file(path_info[4], 'rb')
 
2995
                                try:
 
2996
                                    statvalue = os.fstat(file_obj.fileno())
 
2997
                                    link_or_sha1 = osutils.sha_file(file_obj)
 
2998
                                finally:
 
2999
                                    file_obj.close()
3065
3000
                                self.state._observed_sha1(entry, link_or_sha1,
3066
3001
                                    statvalue)
3067
3002
                            content_change = (link_or_sha1 != source_details[1])
3470
3405
                while (current_entry is not None or
3471
3406
                    current_path_info is not None):
3472
3407
                    if current_entry is None:
3473
 
                        # the check for path_handled when the path is advanced
 
3408
                        # the check for path_handled when the path is adnvaced
3474
3409
                        # will yield this path if needed.
3475
3410
                        pass
3476
3411
                    elif current_path_info is None: