Rev 2321: Move _get_row and _get_block_row_index into Dirstate itself. in http://bazaar.launchpad.net/%7Ebzr/bzr/dirstate

John Arbash Meinel john at arbash-meinel.com
Thu Feb 15 22:29:42 GMT 2007


At http://bazaar.launchpad.net/%7Ebzr/bzr/dirstate

------------------------------------------------------------
revno: 2321
revision-id: john at arbash-meinel.com-20070215222834-dx28dfubjs9d0kd8
parent: john at arbash-meinel.com-20070215202429-gouwaqj9541v25wf
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: dirstate
timestamp: Thu 2007-02-15 16:28:34 -0600
message:
  Move _get_row and _get_block_row_index into Dirstate itself.
modified:
  bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
  bzrlib/tests/test_dirstate.py  test_dirstate.py-20060728012006-d6mvoihjb3je9peu-2
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
-------------- next part --------------
=== modified file 'bzrlib/dirstate.py'
--- a/bzrlib/dirstate.py	2007-02-15 20:24:29 +0000
+++ b/bzrlib/dirstate.py	2007-02-15 22:28:34 +0000
@@ -439,6 +439,53 @@
         self._read_header_if_needed()
         return list(self._parents)
 
+    def _get_row(self, path_utf8):
+        """Get the dirstate row for path.
+
+        :param path_utf8: An utf8 path to be looked up.
+        :return: The dirstate row tuple for path, or (None, None)
+        """
+        self._read_dirblocks_if_needed()
+        if path_utf8 == '':
+            return self._root_row
+        dirname, basename = os.path.split(path_utf8)
+        block_index, row_index, dir_present, file_present = \
+            self._get_block_row_index(dirname, basename)
+        if not file_present:
+            return None, None
+        row = self._dirblocks[block_index][1][row_index]
+        assert row[0][3], 'unversioned row?!?!'
+        return row
+
+    def _get_block_row_index(self, dirname, basename):
+        """Get the coordinates for a path in the state structure.
+
+        :param dirname: The utf8 dirname to lookup.
+        :param basename: The utf8 basename to lookup.
+        :return: A tuple describing where the path is located, or should be
+            inserted. The tuple contains four fields: the block index, the row
+            index, anda two booleans are True when the directory is present, and
+            when the entire path is present.  There is no guarantee that either
+            coordinate is currently reachable unless the found field for it is
+            True. For instance, a directory not present in the state may be
+            returned with a value one greater than the current highest block
+            offset. The directory present field will always be True when the
+            path present field is True.
+        """
+        assert not (dirname == '' and basename == ''), 'blackhole lookup error'
+        self._read_dirblocks_if_needed()
+        block_index = bisect.bisect_left(self._dirblocks, (dirname, []))
+        if (block_index == len(self._dirblocks) or
+            self._dirblocks[block_index][0] != dirname):
+            # no such directory - return the dir index and 0 for the row.
+            return block_index, 0, False, False
+        block = self._dirblocks[block_index][1] # access the rows only
+        search = ((dirname, basename), [])
+        row_index = bisect.bisect_left(block, search)
+        if row_index == len(block) or block[row_index][0][1] != basename:
+            return block_index, row_index, True, False
+        return block_index, row_index, True, True
+
     @staticmethod
     def initialize(path):
         """Create a new dirstate on path.

=== modified file 'bzrlib/tests/test_dirstate.py'
--- a/bzrlib/tests/test_dirstate.py	2007-02-14 06:13:15 +0000
+++ b/bzrlib/tests/test_dirstate.py	2007-02-15 22:28:34 +0000
@@ -474,18 +474,71 @@
         self.assertEqual(expected_rows, list(state._iter_rows()))
 
 
-class TestGetLines(TestCaseWithTransport):
+class TestCaseWithDirstate(TestCaseWithTransport):
+    """Helper functions for creating Dirstate objects with various content."""
+
+    def create_empty_dirstate(self):
+        state = dirstate.DirState.initialize('dirstate')
+        return state
+
+    def create_dirstate_with_root(self):
+        state = self.create_empty_dirstate()
+        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
+        root_row_direntry = ('', '', 'directory', 'a-root-value', 0, packed_stat, '')
+        root_row = (root_row_direntry, [])
+        state._set_data([], root_row, [])
+        return state
+
+    def create_dirstate_with_root_and_subdir(self):
+        state = self.create_dirstate_with_root()
+        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
+        dirblocks = []
+        subdir_row = (('', 'subdir', 'directory', 'subdir-id', 0, packed_stat, ''), [])
+        dirblocks.append(('', [subdir_row]))
+        state._set_data([], state._root_row, dirblocks)
+        return state
+
+    def create_complex_dirstate(self):
+        """This dirstate contains multiple files and directories.
+
+         /        a-root-value
+         a/       a-dir
+         b/       b-dir
+         c        c-file
+         d        d-file
+         a/e/     e-dir
+         a/f      f-file
+         b/g      g-file
+         b/h\xc3\xa5  h-\xc3\xa5-file  #This is u'\xe5' encoded into utf-8
+
+        # Notice that a/e is an empty directory.
+        """
+        state = dirstate.DirState.initialize('dirstate')
+        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
+        null_sha = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
+        root_row_direntry = ('', '', 'directory', 'a-root-value', 0, packed_stat, '')
+        root_row = (root_row_direntry, [])
+        a_row = (('', 'a', 'directory', 'a-dir', 0, packed_stat, ''), [])
+        b_row = (('', 'b', 'directory', 'b-dir', 0, packed_stat, ''), [])
+        c_row = (('', 'c', 'file', 'c-file', 10, packed_stat, null_sha), [])
+        d_row = (('', 'd', 'file', 'd-file', 20, packed_stat, null_sha), [])
+        e_row = (('a', 'e', 'directory', 'e-dir', 0, packed_stat, ''), [])
+        f_row = (('a', 'f', 'file', 'f-file', 30, packed_stat, null_sha), [])
+        g_row = (('b', 'g', 'file', 'g-file', 30, packed_stat, null_sha), [])
+        h_row = (('b', 'h\xc3\xa5', 'file', 'h-\xc3\xa5-file', 40,
+                  packed_stat, null_sha), [])
+        dirblocks = []
+        dirblocks.append(('', [a_row, b_row, c_row, d_row]))
+        dirblocks.append(('a', [e_row, f_row]))
+        dirblocks.append(('b', [g_row, h_row]))
+        state._set_data([], root_row, dirblocks)
+        return state
+
+
+class TestGetLines(TestCaseWithDirstate):
 
     def test_get_line_with_2_rows(self):
-        state = dirstate.DirState.initialize('dirstate')
-        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
-        root_row_direntry = ('', '', 'directory', 'a-root-value', 0, packed_stat, '')
-        root_row = (root_row_direntry, [])
-        dirblocks = []
-        # add a file in the root
-        subdir_row = (['', 'subdir', 'directory', 'subdir-id', 0, packed_stat, ''], [])
-        dirblocks.append(('', [subdir_row]))
-        state._set_data([], root_row, dirblocks)
+        state = self.create_dirstate_with_root_and_subdir()
         self.assertEqual(['#bazaar dirstate flat format 1\n',
             'adler32: 1283137489\n',
             'num_entries: 2\n',
@@ -498,12 +551,9 @@
             state.get_lines())
 
     def test_row_to_line(self):
-        state = dirstate.DirState.initialize('dirstate')
-        packed_stat = 'AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk'
-        root_row_direntry = ('', '', 'directory', 'a-root-value', 0, packed_stat, '')
-        root_parent_direntries = []
-        root_row = (root_row_direntry, root_parent_direntries)
-        self.assertEqual('\x00\x00d\x00a-root-value\x000\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00', state._row_to_line(root_row))
+        state = self.create_dirstate_with_root()
+        self.assertEqual('\x00\x00d\x00a-root-value\x000\x00AAAAREUHaIpFB2iKAAADAQAtkqUAAIGk\x00',
+                         state._row_to_line(state._root_row))
 
     def test_row_to_line_with_parent(self):
         state = dirstate.DirState.initialize('dirstate')
@@ -550,3 +600,101 @@
         state._set_data([], root_row, dirblocks)
         expected_rows = [root_row, subdir_row, afile_row, file_row2]
         self.assertEqual(expected_rows, list(state._iter_rows()))
+
+
+class TestGetBlockRowIndex(TestCaseWithDirstate):
+
+    def assertBlockRowIndexEqual(self, block_index, row_index, dir_present,
+                                 file_present, state, dirname, basename):
+        self.assertEqual((block_index, row_index, dir_present, file_present),
+                         state._get_block_row_index(dirname, basename))
+        if dir_present:
+            block = state._dirblocks[block_index]
+            self.assertEqual(dirname, block[0])
+        if dir_present and file_present:
+            row = state._dirblocks[block_index][1][row_index]
+            self.assertEqual(dirname, row[0][0])
+            self.assertEqual(basename, row[0][1])
+
+    def test_simple_structure(self):
+        state = self.create_dirstate_with_root_and_subdir()
+        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', 'subdir')
+        self.assertBlockRowIndexEqual(0, 0, True, False, state, '', 'bdir')
+        self.assertBlockRowIndexEqual(0, 1, True, False, state, '', 'zdir')
+        self.assertBlockRowIndexEqual(1, 0, False, False, state, 'a', 'foo')
+        self.assertBlockRowIndexEqual(1, 0, False, False, state, 'subdir', 'foo')
+
+    def test_complex_structure_exists(self):
+        state = self.create_complex_dirstate()
+        # Make sure we can find everything that exists
+        self.assertBlockRowIndexEqual(0, 0, True, True, state, '', 'a')
+        self.assertBlockRowIndexEqual(0, 1, True, True, state, '', 'b')
+        self.assertBlockRowIndexEqual(0, 2, True, True, state, '', 'c')
+        self.assertBlockRowIndexEqual(0, 3, True, True, state, '', 'd')
+        self.assertBlockRowIndexEqual(1, 0, True, True, state, 'a', 'e')
+        self.assertBlockRowIndexEqual(1, 1, True, True, state, 'a', 'f')
+        self.assertBlockRowIndexEqual(2, 0, True, True, state, 'b', 'g')
+        self.assertBlockRowIndexEqual(2, 1, True, True, state, 'b', 'h\xc3\xa5')
+
+    def test_complex_structure_missing(self):
+        state = self.create_complex_dirstate()
+        # Make sure things would be inserted in the right locations
+        # '_' comes before 'a'
+        self.assertBlockRowIndexEqual(0, 0, True, False, state, '', '_')
+        self.assertBlockRowIndexEqual(0, 1, True, False, state, '', 'aa')
+        self.assertBlockRowIndexEqual(0, 4, True, False, state, '', 'h\xc3\xa5')
+        self.assertBlockRowIndexEqual(1, 0, False, False, state, '_', 'a')
+        self.assertBlockRowIndexEqual(2, 0, False, False, state, 'aa', 'a')
+        self.assertBlockRowIndexEqual(3, 0, False, False, state, 'bb', 'a')
+        # This would be inserted between a/ and b/
+        self.assertBlockRowIndexEqual(2, 0, False, False, state, 'a/e', 'a')
+        # Put at the end
+        self.assertBlockRowIndexEqual(3, 0, False, False, state, 'e', 'a')
+
+
+class TestGetRow(TestCaseWithDirstate):
+
+    def assertRowEqual(self, dirname, basename, kind, state, path):
+        row = state._get_row(path)
+        if kind is None:
+            self.assertEqual((None, None), row)
+        else:
+            cur = row[0]
+            self.assertEqual((dirname, basename, kind), cur[:3])
+
+    def test_simple_structure(self):
+        state = self.create_dirstate_with_root_and_subdir()
+        self.assertRowEqual('', '', 'directory', state, '')
+        self.assertRowEqual('', 'subdir', 'directory', state, 'subdir')
+        self.assertRowEqual(None, None, None, state, 'missing')
+        self.assertRowEqual(None, None, None, state, 'missing/foo')
+        self.assertRowEqual(None, None, None, state, 'subdir/foo')
+
+    def test_complex_structure_exists(self):
+        state = self.create_complex_dirstate()
+        self.assertRowEqual('', '', 'directory', state, '')
+        self.assertRowEqual('', 'a', 'directory', state, 'a')
+        self.assertRowEqual('', 'b', 'directory', state, 'b')
+        self.assertRowEqual('', 'c', 'file', state, 'c')
+        self.assertRowEqual('', 'd', 'file', state, 'd')
+        self.assertRowEqual('a', 'e', 'directory', state, 'a/e')
+        self.assertRowEqual('a', 'f', 'file', state, 'a/f')
+        self.assertRowEqual('b', 'g', 'file', state, 'b/g')
+        self.assertRowEqual('b', 'h\xc3\xa5', 'file', state, 'b/h\xc3\xa5')
+
+    def test_complex_structure_missing(self):
+        state = self.create_complex_dirstate()
+        self.assertRowEqual(None, None, None, state, '_')
+        self.assertRowEqual(None, None, None, state, '_\xc3\xa5')
+        self.assertRowEqual(None, None, None, state, 'a/b')
+        self.assertRowEqual(None, None, None, state, 'c/d')
+
+    def test_get_row_uninitialized(self):
+        """Calling get_row will load data if it needs to"""
+        state = self.create_dirstate_with_root()
+        state.save()
+        del state
+        state = dirstate.DirState.on_file('dirstate')
+        self.assertEqual(dirstate.DirState.NOT_IN_MEMORY, state._header_state)
+        self.assertEqual(dirstate.DirState.NOT_IN_MEMORY, state._dirblock_state)
+        self.assertRowEqual('', '', 'directory', state, '')

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-02-15 20:24:29 +0000
+++ b/bzrlib/workingtree_4.py	2007-02-15 22:28:34 +0000
@@ -310,18 +310,10 @@
             fileid_utf8 = file_id.encode('utf8')
         if path is not None:
             # path lookups are faster
-            if path == '':
-                return state._root_row
-            dirname, basename = os.path.split(path.encode('utf8'))
-            block_index, row_index, dir_present, file_present = \
-                self._get_block_row_index(dirname, basename)
-            if not file_present:
-                return None, None
-            row = state._dirblocks[block_index][1][row_index]
+            row = state.get_row(path)
             if file_id:
                 if row[0][3] != fileid_utf8:
                     raise BzrError('integrity error ? : mismatching file_id and path')
-            assert row[0][3], 'unversioned row?!?!'
             return row
         else:
             for row in state._iter_rows():



More information about the bazaar-commits mailing list