~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/dirstate.py

  • Committer: John Arbash Meinel
  • Date: 2007-02-21 20:17:10 UTC
  • mto: (2255.2.97 dirstate)
  • mto: This revision was merged to the branch mainline in revision 2322.
  • Revision ID: john@arbash-meinel.com-20070221201710-siq76rbcfpj68gqx
Rewrite the inner parsing loop, needs performance testing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
224
224
     # of using int conversion rather than a dict here. AND BLAME ANDREW IF
225
225
     # it is faster.
226
226
 
 
227
    # TODO: jam 20070221 Make sure we handle when there are duplicated records
 
228
    #       (like when we remove + add the same path, or we have a rename)
 
229
    # TODO: jam 20070221 Figure out what to do if we have a record that exceeds
 
230
    #       the BISECT_PAGE_SIZE.
 
231
    BISECT_PAGE_SIZE = 4096
 
232
 
227
233
    NOT_IN_MEMORY = 0
228
234
    IN_MEMORY_UNMODIFIED = 1
229
235
    IN_MEMORY_MODIFIED = 2
435
441
            entire_entry[tree_offset + 3] = DirState._to_yesno[tree_data[3]]
436
442
        return '\0'.join(entire_entry)
437
443
 
 
444
    def _fields_per_row(self):
 
445
        """How many null separated fields should be in each entry row.
 
446
 
 
447
        Each line now has an extra '\n' field which is not used
 
448
        so we just skip over it
 
449
        entry size:
 
450
            3 fields for the key
 
451
            + number of fields per tree_data (5) * tree count
 
452
            + newline
 
453
         """
 
454
        tree_count = 1 + self._num_present_parents()
 
455
        return 3 + 5 * tree_count + 1
 
456
 
438
457
    def _find_block(self, key, add_if_missing=False):
439
458
        """Return the block that key should be present in.
440
459
 
605
624
        """Create a line for the state file for parents information."""
606
625
        return '\0'.join([str(len(parent_ids))] + parent_ids)
607
626
 
 
627
    def _get_fields_to_entry(self):
 
628
        """Get a function which converts entry fields into a entry record.
 
629
 
 
630
        This handles kind, size, and executable, as well as parent records.
 
631
 
 
632
        :return: A function which takes a list of fields, and returns an
 
633
            appropriate record for storing in memory.
 
634
        """
 
635
        # This is intentionally unrolled for performance
 
636
        num_present_parents = self._num_present_parents()
 
637
        if num_present_parents == 0:
 
638
            def fields_to_entry_0_parents(fields, _int=int, _tuple=tuple,
 
639
                                          _mini_to_kind=self._minikind_to_kind):
 
640
                path_name_file_id_key = _tuple(fields[:3])
 
641
                return (path_name_file_id_key, [
 
642
                    ( # Current tree
 
643
                        _mini_to_kind[fields[3]], # kind
 
644
                        fields[4],                # fingerprint
 
645
                        _int(fields[5]),          # size
 
646
                        fields[6] == 'y',         # executable
 
647
                        fields[7],                # packed_stat or revision_id
 
648
                    )])
 
649
            return fields_to_entry_0_parents
 
650
        elif num_present_parents == 1:
 
651
            def fields_to_entry_1_parent(fields, _int=int, _tuple=tuple,
 
652
                                         _mini_to_kind=self._minikind_to_kind):
 
653
                path_name_file_id_key = _tuple(fields[:3])
 
654
                return (path_name_file_id_key, [
 
655
                    ( # Current tree
 
656
                        _mini_to_kind[fields[3]], # kind
 
657
                        fields[4],                # fingerprint
 
658
                        _int(fields[5]),          # size
 
659
                        fields[6] == 'y',         # executable
 
660
                        fields[7],                # packed_stat or revision_id
 
661
                    ),
 
662
                    ( # Parent 1
 
663
                        _mini_to_kind[fields[8]], # kind
 
664
                        fields[9],                # fingerprint
 
665
                        _int(fields[10]),         # size
 
666
                        fields[11] == 'y',        # executable
 
667
                        fields[12],               # packed_stat or revision_id
 
668
                    ),
 
669
                    ])
 
670
            return fields_to_entry_1_parent
 
671
        elif num_present_parents == 2:
 
672
            def fields_to_entry_2_parents(fields, _int=int, _tuple=tuple,
 
673
                                          _mini_to_kind=self._minikind_to_kind):
 
674
                path_name_file_id_key = _tuple(fields[:3])
 
675
                return (path_name_file_id_key, [
 
676
                    ( # Current tree
 
677
                        _mini_to_kind[fields[3]], # kind
 
678
                        fields[4],                # fingerprint
 
679
                        _int(fields[5]),          # size
 
680
                        fields[6] == 'y',         # executable
 
681
                        fields[7],                # packed_stat or revision_id
 
682
                    ),
 
683
                    ( # Parent 1
 
684
                        _mini_to_kind[fields[8]], # kind
 
685
                        fields[9],                # fingerprint
 
686
                        _int(fields[10]),         # size
 
687
                        fields[11] == 'y',        # executable
 
688
                        fields[12],               # packed_stat or revision_id
 
689
                    ),
 
690
                    ( # Parent 2
 
691
                        _mini_to_kind[fields[13]],# kind
 
692
                        fields[14],               # fingerprint
 
693
                        _int(fields[15]),         # size
 
694
                        fields[16] == 'y',        # executable
 
695
                        fields[17],               # packed_stat or revision_id
 
696
                    ),
 
697
                    ])
 
698
            return fields_to_entry_2_parents
 
699
        else:
 
700
            def fields_to_entry_n_parents(fields, _int=int, _tuple=tuple,
 
701
                                          _mini_to_kind=self._minikind_to_kind):
 
702
                path_name_file_id_key = _tuple(fields[:3])
 
703
                trees = [(_mini_to_kind[fields[cur]], # kind
 
704
                          fields[cur+1],              # fingerprint
 
705
                          _int(fields[cur+2]),        # size
 
706
                          fields[cur+3] == 'y',       # executable
 
707
                          fields[cur+4],              # stat or revision_id
 
708
                         ) for cur in xrange(3, len(fields)-1, 5)]
 
709
                return path_name_file_id_key, trees
 
710
            return fields_to_entry_n_parents
 
711
 
608
712
    def get_parent_ids(self):
609
713
        """Return a list of the parent tree ids for the directory state."""
610
714
        self._read_header_if_needed()
799
903
        return ('/', 'RECYCLED.BIN', 'file', fileid_utf8, 0, DirState.NULLSTAT,
800
904
            ''), parents
801
905
 
 
906
    def _num_present_parents(self):
 
907
        """The number of parent entries in each record row."""
 
908
        return len(self._parents) - len(self._ghosts)
 
909
 
802
910
    @staticmethod
803
911
    def on_file(path):
804
912
        """Construct a DirState on the file at path path."""
834
942
            #  3 fields for the key
835
943
            #  + number of fields per tree_data (5) * tree count
836
944
            #  + newline
837
 
            num_present_parents = len(self._parents) - len(self._ghosts)
 
945
            num_present_parents = self._num_present_parents()
838
946
            tree_count = 1 + num_present_parents
839
 
            entry_size = 3 + 5 * tree_count + 1
 
947
            entry_size = self._fields_per_row()
840
948
            expected_field_count = entry_size * self._num_entries
841
949
            if len(fields) - cur > expected_field_count:
842
950
                fields = fields[:expected_field_count + cur]
850
958
                    field_count - cur, expected_field_count, entry_size,
851
959
                    self._num_entries, fields)
852
960
 
853
 
            # Fast path the case where there are 1 or 2 parents
854
 
            if num_present_parents == 0:
855
 
                # key, [current tree]
856
 
                entries = [(tuple(fields[pos:pos + 3]), [fields[pos + 3:pos + 8]])
857
 
                    for pos in xrange(cur, field_count, entry_size)]
858
 
            elif num_present_parents == 1:
859
 
                # key,
860
 
                entries = [(tuple(fields[pos:pos + 3]),
861
 
                #   [current tree,             parent 1]
862
 
                    [fields[pos + 3:pos + 8], fields[pos + 8:pos + 13], ])
863
 
                    for pos in xrange(cur, field_count, entry_size)]
864
 
            elif num_present_parents == 2:
865
 
                # key,
866
 
                entries = [(tuple(fields[pos:pos + 3]),
867
 
                #   [current tree,             parent 1, 
868
 
                    [fields[pos + 3:pos + 8], fields[pos + 8:pos + 13],
869
 
                #   parent 2]
870
 
                    fields[pos + 13:pos + 18], ])
871
 
                    for pos in xrange(cur, field_count, entry_size)]
872
 
            else:
873
 
                entries = [(
874
 
                    tuple(fields[pos:pos+3]), #key
875
 
                    tuple([fields[chunk:chunk+5] for 
876
 
                        chunk in xrange(pos + 3, pos+entry_size-1, 5)]))
877
 
                            for pos in xrange(cur, field_count, entry_size)
878
 
                ]
879
 
 
880
 
            assert len(entries) == self._num_entries, '%s != %s entries' % (len(entries),
881
 
                self._num_entries)
882
 
 
883
 
            def _line_to_entry(line):
884
 
                """Convert freshly read tree details to the final form.
885
 
                
886
 
                This converts size and minikind for use and makes it into a 
887
 
                tuple.
888
 
                """
889
 
                for tree in line[1]:
890
 
                    # convert the minikind to kind
891
 
                    tree[0] = self._minikind_to_kind[tree[0]]
892
 
                    # convert the size to an int
893
 
                    tree[2] = int(tree[2])
894
 
                    tree[3] = tree[3] == 'y'
895
 
                return line[0], map(tuple, line[1])
896
 
            new_entries = map(_line_to_entry, entries)
897
 
            self._entries_to_current_state(new_entries)
 
961
            fields_to_entry = self._get_fields_to_entry()
 
962
            entries = [fields_to_entry(fields[pos:pos+entry_size])
 
963
                       for pos in xrange(cur, field_count, entry_size)]
 
964
            self._entries_to_current_state(entries)
898
965
            self._dirblock_state = DirState.IN_MEMORY_UNMODIFIED
899
966
 
900
967
    def _read_header(self):