~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/dirstate.py

Restore dirstate to all tests passing condition.

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
OR (for non tree-0)
66
66
entry[1][1][4]: revision_id
67
67
 
68
 
There may be multiple rows at the root, one per id present in the root, so the in memory root row is now:
69
 
_root_entries[0][0]: ''
70
 
_root_entries[0][1]: ''
71
 
_root_entries[0][2]: file_id
72
 
_root_entries[1][0]: The tree data for the current tree for this fileid at /
 
68
There may be multiple rows at the root, one per id present in the root, so the
 
69
in memory root row is now:
 
70
self._dirblocks[0] -> ('', [entry ...]),
 
71
and the entries in there are
 
72
entries[0][0]: ''
 
73
entries[0][1]: ''
 
74
entries[0][2]: file_id
 
75
entries[1][0]: The tree data for the current tree for this fileid at /
73
76
etc.
74
77
 
75
78
Kinds:
262
265
        self._dirblocks = []
263
266
        self._ghosts = []
264
267
        self._parents = []
265
 
        self._root_entries = None
266
268
        self._state_file=None
267
269
 
268
270
    def add(self, path, file_id, kind, stat, link_or_sha1):
298
300
        # faster than three separate encodes.
299
301
        utf8path = (dirname + '/' + basename).strip('/').encode('utf8')
300
302
        dirname, basename = os.path.split(utf8path)
 
303
        entry_key = (dirname, basename, file_id.encode('utf8'))
301
304
        self._read_dirblocks_if_needed()
302
 
        block_index = self._find_dirblock_index(dirname)
303
 
        if block_index < 0:
 
305
        block_index, present = self._find_block_index_from_key(entry_key)
 
306
        if not present:
 
307
            # TODO: This test is not complete - an empty directory, or a
 
308
            # directory for a parent tree will fool it.
304
309
            # some parent path has not been added - its an error to add this
305
310
            # child
306
311
            raise errors.NotVersionedError(path, str(self))
312
317
            size = stat.st_size
313
318
            packed_stat = pack_stat(stat)
314
319
        parent_info = self._empty_parent_info()
315
 
        entry_key = (dirname, basename, file_id.encode('utf8'))
316
320
        if kind == 'file':
317
321
            entry_data = entry_key, [
318
322
                (kind, link_or_sha1, size, False, packed_stat),
327
331
                ] + parent_info
328
332
        else:
329
333
            raise errors.BzrError('unknown kind %r' % kind)
330
 
        entry_index = bisect.bisect_left(block, entry_data)
331
 
        if len(block) > entry_index:
332
 
            assert block[entry_index][0][1] != basename, \
333
 
                "basename %r already added" % basename
 
334
        entry_index, present = self._find_entry_index(entry_key, block)
 
335
        assert not present, "basename %r already added" % basename
334
336
        block.insert(entry_index, entry_data)
335
337
 
336
338
        if kind == 'directory':
338
340
           self._ensure_block(block_index, entry_index, utf8path)
339
341
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
340
342
 
341
 
    def add_deleted(self, fileid_utf8, parents):
342
 
        """Add fileid_utf8 with parents as deleted."""
343
 
        raise Exception, "broken"
344
 
        self._read_dirblocks_if_needed()
345
 
        new_row = self._make_deleted_row(fileid_utf8, parents)
346
 
        block_index = self._find_dirblock_index(new_row[0][0])
347
 
        if block_index < 0:
348
 
            # no deleted block yet.
349
 
            bisect.insort_left(self._dirblocks, (new_row[0][0], []))
350
 
            block_index = self._find_dirblock_index(new_row[0][0])
351
 
        block = self._dirblocks[block_index][1]
352
 
        row_index = bisect.insort_left(block, new_row)
353
 
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
354
 
 
355
343
    def _empty_parent_info(self):
356
344
        return [DirState.NULL_PARENT_DETAILS] * (len(self._parents) -
357
345
                                                    len(self._ghosts))
376
364
        :param dirname: The utf8 dirname to ensure there is a block for.
377
365
        :return: The index for the block.
378
366
        """
 
367
        assert dirname != ''
379
368
        # the basename of the directory must be the end of its full name.
380
369
        if not (parent_block_index == -1 and
381
370
            parent_block_index == -1 and dirname == ''):
382
371
            assert dirname.endswith(
383
372
                self._dirblocks[parent_block_index][1][parent_row_index][0][1])
384
 
        ## In future, when doing partial parsing, this should load and 
385
 
        # populate the entire block.
386
 
        index = bisect.bisect_left(self._dirblocks, (dirname, []))
387
 
        if (index == len(self._dirblocks) or
388
 
            self._dirblocks[index][0] != dirname):
389
 
            self._dirblocks.insert(index, (dirname, []))
390
 
        return index
 
373
        block_index, present = self._find_block_index_from_key((dirname, '', ''))
 
374
        if not present:
 
375
            ## In future, when doing partial parsing, this should load and 
 
376
            # populate the entire block.
 
377
            self._dirblocks.insert(block_index, (dirname, []))
 
378
        return block_index
391
379
 
392
380
    def _entries_to_current_state(self, new_entries):
393
 
        """Load new_entries into self._root_entries and self.dirblocks.
 
381
        """Load new_entries into self.dirblocks.
394
382
 
395
383
        Process new_entries into the current state object, making them the active
396
384
        state.
401
389
        """
402
390
        assert new_entries[0][0][0:2] == ('', ''), \
403
391
            "Missing root row %r" % new_entries[0][0]
404
 
        self._root_entries = []
405
 
        self._dirblocks = [('', [])]
406
 
        current_block = self._root_entries
 
392
        # The two blocks here are deliberate: the root block and the 
 
393
        # contents-of-root block.
 
394
        self._dirblocks = [('', []), ('', [])]
 
395
        current_block = self._dirblocks[0][1]
407
396
        current_dirname = ''
408
397
        root_key = ('', '')
409
398
        for entry in new_entries:
410
399
            if entry[0][0] != current_dirname:
411
 
                # new block
 
400
                # new block - different dirname
412
401
                current_block = []
413
402
                current_dirname = entry[0][0]
414
403
                self._dirblocks.append((current_dirname, current_block))
415
 
            elif entry[0][0:2] != root_key:
416
 
                # this is not a root entry for a tree
 
404
            elif entry[0][1]:
 
405
                # this is not a root entry for a tree (it has a basename)
417
406
                current_block = self._dirblocks[-1][1]
418
407
            # append the entry to the current block
419
408
            current_block.append(entry)
443
432
        :param key: A dirstate entry key.
444
433
        :return: The block tuple.
445
434
        """
446
 
        if key[0:2] == ('', ''):
447
 
            return ('', self._root_entries)
448
 
        else:
449
 
            block_index, present = self._find_block_index_from_key(key)
450
 
            if not present:
451
 
                if add_if_missing:
452
 
                    self._dirblocks.insert(block_index, (key[0], []))
453
 
                else:
454
 
                    # some parent path has not been added - its an error to add this
455
 
                    # child
456
 
                    raise errors.NotVersionedError(key[0:2], str(self))
457
 
            return self._dirblocks[block_index]
 
435
        block_index, present = self._find_block_index_from_key(key)
 
436
        if not present:
 
437
            if add_if_missing:
 
438
                self._dirblocks.insert(block_index, (key[0], []))
 
439
            else:
 
440
                # some parent path has not been added - its an error to add this
 
441
                # child
 
442
                raise errors.NotVersionedError(key[0:2], str(self))
 
443
        return self._dirblocks[block_index]
458
444
 
459
445
    def _find_block_index_from_key(self, key):
460
446
        """Find the dirblock index for a key.
461
447
 
462
448
        :return: The block index, True if the block for the key is present.
463
449
        """
464
 
        block_index = bisect.bisect_left(self._dirblocks, (key[0], []))
 
450
        if key[0:2] == ('', ''):
 
451
            return 0, True
 
452
        block_index = bisect.bisect_left(self._dirblocks, (key[0], []), 1)
 
453
        # _right returns one-past-where-key is so we have to subtract
 
454
        # one to use it. we use _right here because there are two
 
455
        # '' blocks - the root, and the contents of root
 
456
        # we always have a minimum of 2 in self._dirblocks: root and
 
457
        # root-contents, and for '', we get 2 back, so this is 
 
458
        # simple and correct:
465
459
        present = (block_index < len(self._dirblocks) and
466
460
            self._dirblocks[block_index][0] == key[0])
467
461
        return block_index, present
468
462
 
469
 
    def _find_dirblock_index(self, dirname):
470
 
        """Find the dirblock index for dirname.
471
 
 
472
 
        :return: -1 if the dirname is not present, or the index in
473
 
            self._dirblocks for it otherwise.
474
 
        """
475
 
        block_index = bisect.bisect_left(self._dirblocks, (dirname, []))
476
 
        if (block_index == len(self._dirblocks) or
477
 
            self._dirblocks[block_index][0] != dirname):
478
 
            return -1
479
 
        return block_index
480
 
 
481
463
    def _find_entry_index(self, key, block):
482
464
        """Find the entry index for a key in a block.
483
465
 
495
477
        :param tree: The tree which should provide parent information and
496
478
            inventory ids.
497
479
        """
 
480
        result = DirState.initialize(dir_state_filename)
498
481
        tree.lock_read()
499
 
        # XXX: aka the big ugly.: To fix this, turn it into:
500
 
        # init; set_path_id(root); set_parents(tree.get_parnets); write_inventory(tree.inventory)
501
 
        result = DirState()
502
 
        result._state_file = open(dir_state_filename, 'wb+')
503
 
 
504
 
        _encode = base64.encodestring
505
 
 
506
482
        parent_ids = tree.get_parent_ids()
507
483
        num_parents = len(parent_ids)
508
 
        if num_parents > 3:
509
 
            raise ValueError('Cannot handle more than 3 parents')
510
 
 
511
484
        parent_trees = []
512
485
        for parent_id in parent_ids:
513
 
            parent_trees.append(tree.branch.repository.revision_tree(parent_id))
514
 
            parent_trees[-1].lock_read()
515
 
        all_trees = [tree] + parent_trees
516
 
        num_trees = len(all_trees)
517
 
 
518
 
        # FIXME: is this utf8 safe?
519
 
 
520
 
        to_minikind = DirState._kind_to_minikind
521
 
        to_yesno = DirState._to_yesno
522
 
 
523
 
        st = os.lstat(tree.basedir)
524
 
        root_entries = []
525
 
        dirblocks = []
526
 
        for tree_index, tree in enumerate(all_trees):
527
 
            for path, tree_entry in tree.iter_entries_by_dir():
528
 
                dirname, basename = os.path.split(path.encode('utf8'))
529
 
                file_id = tree_entry.file_id.encode('utf8')
530
 
                kind = tree_entry.kind
531
 
                if kind == 'directory':
532
 
                    fingerprint = ''
533
 
                    size = 0
534
 
                    executable = False
535
 
                elif kind == 'symlink':
536
 
                    fingerprint = tree.symlink_target(path)
537
 
                    size = 0
538
 
                    executable = False
539
 
                elif kind == 'file':
540
 
                    fingerprint = tree.get_file_sha1(tree_entry.file_id, path)
541
 
                    size = tree_entry.text_size
542
 
                    executable = tree.is_executable(tree_entry.file_id, path)
543
 
                else:
544
 
                    raise Exception
545
 
 
546
 
                key = (dirname, basename, file_id)
547
 
                if (dirname, basename) == ('', ''):
548
 
                    block = root_entries
549
 
                else:
550
 
                    # not a root entry
551
 
                    block_index = bisect.bisect_left(dirblocks, (dirname, []))
552
 
                    if block_index == len(dirblocks) or dirblocks[block_index][0] != dirname:
553
 
                        # no dirblock yet.
554
 
                        dirblocks.insert(block_index, (dirname, []))
555
 
                    block = dirblocks[block_index][1]
556
 
                # find the data for this path within block:
557
 
                entry_index = bisect.bisect_left(block, (key,))
558
 
                if entry_index == len(block) or block[entry_index][0] != key:
559
 
                    # new key in this block, add blank data
560
 
                    block.insert(entry_index, (key, [None] * num_trees))
561
 
                # get the right form of data for this trees type
562
 
                if tree_index == 0:
563
 
                    # current tree
564
 
                    st = os.lstat(tree.abspath(path))
565
 
                    tree_data = pack_stat(st)
566
 
                    if kind == 'file':
567
 
                        size = st.st_size
568
 
                else:
569
 
                    tree_data = tree_entry.revision.encode('utf8')
570
 
                block[entry_index][1][tree_index] = (
571
 
                    kind,
572
 
                    fingerprint,
573
 
                    size,
574
 
                    executable,
575
 
                    tree_data)
576
 
 
577
 
        result._set_data(parent_ids, root_entries, dirblocks)
578
 
        result.save()
579
 
        for tree in all_trees:
580
 
            tree.unlock()
 
486
            parent_trees.append((parent_id, tree.branch.repository.revision_tree(parent_id)))
 
487
            parent_trees[-1][1].lock_read()
 
488
        result.set_parent_trees(parent_trees, [])
 
489
        result.set_state_from_inventory(tree.inventory)
 
490
 
 
491
        for revid, parent in parent_trees:
 
492
            parent.unlock()
 
493
        tree.unlock()
581
494
        return result
582
495
 
583
496
    def get_ghosts(self):
632
545
            rather it indicates that there are at least some files in some
633
546
            tree present there.
634
547
        """
635
 
        # looking up the root is not supported, because the root entries exist
636
 
        # outside the used coordinate system
637
 
        assert not (dirname == '' and basename == ''), 'blackhole lookup error'
638
548
        self._read_dirblocks_if_needed()
639
 
        block_index = bisect.bisect_left(self._dirblocks, (dirname, []))
640
 
        if (block_index == len(self._dirblocks) or
641
 
            self._dirblocks[block_index][0] != dirname):
 
549
        key = dirname, basename, ''
 
550
        block_index, present = self._find_block_index_from_key(key)
 
551
        if not present:
642
552
            # no such directory - return the dir index and 0 for the row.
643
553
            return block_index, 0, False, False
644
554
        block = self._dirblocks[block_index][1] # access the entries only
645
 
        search = ((dirname, basename),)
646
 
        row_index = bisect.bisect_left(block, search)
 
555
        entry_index, present = self._find_entry_index(key, block)
647
556
        # linear search through present entries at this path to find the one
648
557
        # requested.
649
 
        while row_index < len(block) and block[row_index][0][1] == basename:
650
 
            if block[row_index][1][tree_index][0] not in \
 
558
        while entry_index < len(block) and block[entry_index][0][1] == basename:
 
559
            if block[entry_index][1][tree_index][0] not in \
651
560
                       ('absent', 'relocated'):
652
 
                return block_index, row_index, True, True
653
 
            row_index += 1
654
 
        return block_index, row_index, True, False
 
561
                return block_index, entry_index, True, True
 
562
            entry_index += 1
 
563
        return block_index, entry_index, True, False
655
564
 
656
565
    def _get_entry(self, tree_index, fileid_utf8=None, path_utf8=None):
657
566
        """Get the dirstate entry for path in tree tree_index
671
580
        if path_utf8 is not None:
672
581
            assert path_utf8.__class__ == str, 'path_utf8 is not a str: %s %s' % (type(path_utf8), path_utf8)
673
582
            # path lookups are faster
674
 
            if path_utf8 == '':
675
 
                for entry in self._root_entries:
676
 
                    if entry[1][tree_index] not in ('absent', 'relocated'):
677
 
                        return entry
678
 
                raise Exception, 'rootless trees not supported yet'
679
583
            dirname, basename = os.path.split(path_utf8)
680
584
            block_index, entry_index, dir_present, file_present = \
681
585
                self._get_block_entry_index(dirname, basename, tree_index)
718
622
        # persist.
719
623
        result = DirState()
720
624
        result._state_file = open(path, 'wb+')
 
625
        # root dir and root dir contents with no children.
 
626
        empty_tree_dirblocks = [('', []), ('', [])]
721
627
        # a new root directory, with a NULLSTAT.
722
 
        root_entries = [(('', '', bzrlib.inventory.ROOT_ID), [
 
628
        empty_tree_dirblocks[0][1].append(
 
629
            (('', '', bzrlib.inventory.ROOT_ID), [
723
630
                ('directory', '', 0, False, DirState.NULLSTAT),
724
 
            ])]
725
 
        root_parents = []
726
 
        empty_tree_dirblocks = [('', [])] # root dir contents - no entries.
727
 
        result._set_data([], root_entries, empty_tree_dirblocks)
 
631
            ]))
 
632
        result._set_data([], empty_tree_dirblocks)
728
633
        try:
729
634
            result.save()
730
635
        except:
759
664
            raise Exception
760
665
        return (kind, fingerprint, size, executable, tree_data)
761
666
 
762
 
    def _iter_entries(self, root_entries=None, dirblocks=None):
 
667
    def _iter_entries(self):
763
668
        """Iterate over all the entries in the dirstate.
764
669
 
765
670
        Each yelt item is an entry in the standard format described in the
766
671
        docstring of bzrlib.dirstate.
767
 
 
768
 
        :param root_entries: Allows overriding of the root entries to be
769
 
            reported.
770
 
        :param dirblocks: Allows overriding of the source dirblock data.
771
672
        """
772
673
        self._read_dirblocks_if_needed()
773
 
        if root_entries is None:
774
 
            root_entries = self._root_entries
775
 
        if dirblocks is None:
776
 
            dirblocks = self._dirblocks
777
 
        for entry in root_entries:
778
 
            yield entry
779
 
        for directory in dirblocks:
 
674
        for directory in self._dirblocks:
780
675
            for entry in directory[1]:
781
676
                yield entry
782
677
 
 
678
    def _get_id_index(self):
 
679
        """Get an id index of self._dirblocks."""
 
680
        id_index = {}
 
681
        for key, tree_details in self._iter_entries():
 
682
            id_index.setdefault(key[2], set()).add(key)
 
683
        return id_index
 
684
 
783
685
    def _get_output_lines(self, lines):
784
686
        """format lines for final output.
785
687
 
811
713
    def _read_dirblocks_if_needed(self):
812
714
        """Read in all the dirblocks from the file if they are not in memory.
813
715
        
814
 
        This populates self._root_entries and self._dirblocks, and sets 
815
 
        self._dirblock_state to IN_MEMORY_UNMODIFIED. It is not currently ready
816
 
        for incremental block loading.
 
716
        This populates self._dirblocks, and sets self._dirblock_state to
 
717
        IN_MEMORY_UNMODIFIED. It is not currently ready for incremental block
 
718
        loading.
817
719
        """
818
720
        self._read_header_if_needed()
819
721
        if self._dirblock_state == DirState.NOT_IN_MEMORY:
969
871
            self._header_state = DirState.IN_MEMORY_UNMODIFIED
970
872
            self._dirblock_state = DirState.IN_MEMORY_UNMODIFIED
971
873
 
972
 
    def _set_data(self, parent_ids, root_entries, dirblocks):
 
874
    def _set_data(self, parent_ids, dirblocks):
973
875
        """Set the full dirstate data in memory.
974
876
 
975
877
        This is an internal function used to completely replace the objects
976
878
        in memory state. It puts the dirstate into state 'full-dirty'.
977
879
 
978
880
        :param parent_ids: A list of parent tree revision ids.
979
 
        :param root_entrie: The root entries: A list of entries, one per fileid found
980
 
            at the root.
981
881
        :param dirblocks: A list containing one tuple for each directory in the
982
882
            tree. Each tuple contains the directory path and a list of entries 
983
883
            found in that directory.
984
884
        """
985
885
        # our memory copy is now authoritative.
986
886
        self._dirblocks = dirblocks
987
 
        self._root_entries = root_entries
988
887
        self._header_state = DirState.IN_MEMORY_MODIFIED
989
888
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
990
889
        self._parents = list(parent_ids)
1007
906
            # logic not written
1008
907
            raise NotImplementedError(self.set_path_id)
1009
908
        # TODO: check new id is unique
1010
 
        entry = self._get_entry(0, path_utf8='')
1011
 
        # TODO: version of _get_block_entry_index that works with the root so
1012
 
        # we dont look up this twice.
1013
 
        index = self._root_entries.index(entry)
1014
 
        if new_id == entry[0][2]:
1015
 
            # no change
1016
 
            return
1017
 
        if len(entry[1]) > 1:
1018
 
            # TODO: split the record.
1019
 
            raise NotImplementedError(self.set_path_id)
1020
 
            root_info, root_parents = self._root_entrie
1021
 
            if len(root_parents):
1022
 
                self.add_deleted(root_info[3], root_parents)
1023
 
        # replace the entry:
1024
 
        self._root_entries[index] = (('', '', new_id), entry[1])
 
909
        entry = self._get_entry(0, path_utf8=path)
 
910
        # mark the old path absent, and insert a new root path
 
911
        present_parents = len(entry[1]) - 1
 
912
        self._make_absent(entry)
 
913
        id_index = self._get_id_index()
 
914
        self.update_minimal(('', '', new_id), 'directory', present_parents,
 
915
            path_utf8='', id_index=id_index, packed_stat=entry[1][0][4])
1025
916
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1026
917
 
1027
918
    def set_parent_trees(self, trees, ghosts):
1040
931
        # all by path in parallel for 'optimal' common-case performance.
1041
932
        # generate new root row.
1042
933
        self._read_dirblocks_if_needed()
1043
 
        old_roots = self._root_entries
1044
 
        root_info = self._root_entries[0]
1045
 
        new_parent_count = len(trees)
1046
934
        # TODO future sketch: Examine the existing parents to generate a change
1047
935
        # map and then walk the new parent trees only, mapping them into the
1048
936
        # dirstate. Walk the dirstate at the same time to remove unreferenced
1177
1065
        self._read_dirblocks_if_needed()
1178
1066
        # sketch:
1179
1067
        #  generate a byid index of the dirstate
1180
 
        id_index = {}
1181
 
        for key, tree_details in self._iter_entries():
1182
 
            id_index.setdefault(key[2], set()).add(key)
 
1068
        id_index = self._get_id_index()
1183
1069
 
1184
1070
        num_present_parents = len(self._parents) - len(self._ghosts)
1185
1071
        # incremental algorithm:
1297
1183
            # it must not be absent at the moment
1298
1184
            assert update_tree_details[0][0] != 'absent'
1299
1185
            update_tree_details[0] = DirState.NULL_PARENT_DETAILS
 
1186
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1300
1187
        return last_reference
1301
1188
 
1302
1189
    def update_minimal(self, key, kind, num_present_parents, executable=False,
1303
1190
        fingerprint='', packed_stat=None, size=0, id_index=None,
1304
1191
        path_utf8=None):
1305
1192
        """Update an entry to the state in tree 0."""
1306
 
        if key[0:2] == ('', ''):
1307
 
            block = self._root_entries
1308
 
        else:
1309
 
            block = self._find_block(key)[1]
 
1193
        block = self._find_block(key)[1]
1310
1194
        if packed_stat is None:
1311
1195
            packed_stat = DirState.NULLSTAT
1312
1196
        entry_index, present = self._find_entry_index(key, block)
1313
1197
        new_details = (kind, fingerprint, size, executable, packed_stat)
1314
 
        assert id_index, 'need an id index to do updates for now !'
 
1198
        assert id_index is not None, 'need an id index to do updates for now !'
1315
1199
        if not present:
1316
1200
            # new entry, synthesis cross reference here,
1317
1201
            existing_keys = id_index.setdefault(key[2], set())
1333
1217
                    assert present
1334
1218
                    other_entry_index, present = self._find_entry_index(other_key, self._dirblocks[other_block_index][1])
1335
1219
                    assert present
 
1220
                    assert path_utf8 is not None
1336
1221
                    self._dirblocks[other_block_index][1][other_entry_index][1][0] = \
1337
1222
                        ('relocated', path_utf8, 0, False, '')
1338
1223
 
1386
1271
                    assert present
1387
1272
                    self._dirblocks[block_index][1][entry_index][1][0] = \
1388
1273
                        ('relocated', path_utf8, 0, False, '')
 
1274
        # add a containing dirblock if needed.
 
1275
        if new_details[0] == 'directory':
 
1276
            subdir_key = (os.path.join(*key[0:2]), '', '')
 
1277
            block_index, present = self._find_block_index_from_key(subdir_key)
 
1278
            if not present:
 
1279
                self._dirblocks.insert(block_index, (subdir_key[0], []))
1389
1280
 
1390
1281
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1391
1282