def test_tree_reference(self): s_v5 = bzrlib.xml5.serializer_v5 s_v6 = bzrlib.xml6.serializer_v6 s_v7 = xml7.serializer_v7 inv = Inventory('tree-root-321', revision_id='rev-outer') inv.root.revision = 'root-rev' inv.add( inventory.TreeReference('nested-id', 'nested', 'tree-root-321', 'rev-outer', 'rev-inner')) self.assertRaises(errors.UnsupportedInventoryKind, s_v5.write_inventory_to_string, inv) self.assertRaises(errors.UnsupportedInventoryKind, s_v6.write_inventory_to_string, inv) txt = s_v7.write_inventory_to_string(inv) lines = s_v7.write_inventory_to_lines(inv) self.assertEqual(bzrlib.osutils.split_lines(txt), lines) inv2 = s_v7.read_inventory_from_string(txt) self.assertEqual('tree-root-321', inv2['nested-id'].parent_id) self.assertEqual('rev-outer', inv2['nested-id'].revision) self.assertEqual('rev-inner', inv2['nested-id'].reference_revision) self.assertRaises(errors.UnsupportedInventoryKind, s_v6.read_inventory_from_string, txt.replace('format="7"', 'format="6"')) self.assertRaises(errors.UnsupportedInventoryKind, s_v5.read_inventory_from_string, txt.replace('format="7"', 'format="5"'))
def test_roundtrip_inventory_v7(self): inv = self.get_sample_inventory() inv.add( inventory.TreeReference('nested-id', 'nested', 'tree-root-321', 'rev_outer', 'rev_inner')) txt = xml7.serializer_v7.write_inventory_to_string(inv) lines = xml7.serializer_v7.write_inventory_to_lines(inv) self.assertEqual(bzrlib.osutils.split_lines(txt), lines) self.assertEqualDiff(_expected_inv_v7, txt) inv2 = xml7.serializer_v7.read_inventory_from_string(txt) self.assertEqual(5, len(inv2)) for path, ie in inv.iter_entries(): self.assertEqual(ie, inv2[ie.file_id])
def _unpack_entry(self, elt): kind = elt.tag if not kind in self.supported_kinds: raise AssertionError('unsupported entry kind %s' % kind) if kind == 'tree-reference': file_id = elt.attrib['file_id'] name = elt.attrib['name'] parent_id = elt.attrib['parent_id'] revision = elt.get('revision') reference_revision = elt.get('reference_revision') return inventory.TreeReference(file_id, name, parent_id, revision, reference_revision) else: return xml6.Serializer_v6._unpack_entry(self, elt)
def unpack_inventory_entry(elt, entry_cache=None, return_from_cache=False): elt_get = elt.get file_id = elt_get('file_id') revision = elt_get('revision') # Check and see if we have already unpacked this exact entry # Some timings for "repo.revision_trees(last_100_revs)" # bzr mysql # unmodified 4.1s 40.8s # using lru 3.5s # using fifo 2.83s 29.1s # lru._cache 2.8s # dict 2.75s 26.8s # inv.add 2.5s 26.0s # no_copy 2.00s 20.5s # no_c,dict 1.95s 18.0s # Note that a cache of 10k nodes is more than sufficient to hold all of # the inventory for the last 100 revs for bzr, but not for mysql (20k # is enough for mysql, which saves the same 2s as using a dict) # Breakdown of mysql using time.clock() # 4.1s 2 calls to element.get for file_id, revision_id # 4.5s cache_hit lookup # 7.1s InventoryFile.copy() # 2.4s InventoryDirectory.copy() # 0.4s decoding unique entries # 1.6s decoding entries after FIFO fills up # 0.8s Adding nodes to FIFO (including flushes) # 0.1s cache miss lookups # Using an LRU cache # 4.1s 2 calls to element.get for file_id, revision_id # 9.9s cache_hit lookup # 10.8s InventoryEntry.copy() # 0.3s cache miss lookus # 1.2s decoding entries # 1.0s adding nodes to LRU if entry_cache is not None and revision is not None: key = (file_id, revision) try: # We copy it, because some operations may mutate it cached_ie = entry_cache[key] except KeyError: pass else: # Only copying directory entries drops us 2.85s => 2.35s if return_from_cache: if cached_ie.kind == 'directory': return cached_ie.copy() return cached_ie return cached_ie.copy() kind = elt.tag if not inventory.InventoryEntry.versionable_kind(kind): raise AssertionError('unsupported entry kind %s' % kind) file_id = get_utf8_or_ascii(file_id) if revision is not None: revision = get_utf8_or_ascii(revision) parent_id = elt_get('parent_id') if parent_id is not None: parent_id = get_utf8_or_ascii(parent_id) if kind == 'directory': ie = inventory.InventoryDirectory(file_id, elt_get('name'), parent_id) elif kind == 'file': ie = inventory.InventoryFile(file_id, elt_get('name'), parent_id) ie.text_sha1 = elt_get('text_sha1') if elt_get('executable') == 'yes': ie.executable = True v = elt_get('text_size') ie.text_size = v and int(v) elif kind == 'symlink': ie = inventory.InventoryLink(file_id, elt_get('name'), parent_id) ie.symlink_target = elt_get('symlink_target') elif kind == 'tree-reference': file_id = elt.attrib['file_id'] name = elt.attrib['name'] parent_id = elt.attrib['parent_id'] revision = elt.get('revision') reference_revision = elt.get('reference_revision') ie = inventory.TreeReference(file_id, name, parent_id, revision, reference_revision) else: raise errors.UnsupportedInventoryKind(kind) ie.revision = revision if revision is not None and entry_cache is not None: # We cache a copy() because callers like to mutate objects, and # that would cause the item in cache to mutate as well. # This has a small effect on many-inventory performance, because # the majority fraction is spent in cache hits, not misses. entry_cache[key] = ie.copy() return ie