~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/xml8.py

  • Committer: John Arbash Meinel
  • Date: 2008-12-12 20:06:28 UTC
  • mto: This revision was merged to the branch mainline in revision 3912.
  • Revision ID: john@arbash-meinel.com-20081212200628-xmm9i33jq3d6tsh3
Start moving things around so that the entry cache is passed in.

This has a negligible effect on performance, and means that we can have the
cache lifetime associated with a repository, rather than 'always on'.

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
    "<":"&lt;",
41
41
    ">":"&gt;",
42
42
    }
 
43
_entry_cache = fifo_cache.FIFOCache(10*1024)
43
44
 
44
45
 
45
46
def _ensure_utf8_re():
146
147
    Its revision format number matches its inventory number.
147
148
    """
148
149
 
149
 
    __slots__ = ['_entry_cache']
 
150
    __slots__ = []
150
151
 
151
152
    root_id = None
152
153
    support_altered_by_hack = True
157
158
    format_num = '8'
158
159
    revision_format_num = None
159
160
 
160
 
    def __init__(self):
161
 
        self._entry_cache = fifo_cache.FIFOCache(10*1024)
162
 
 
163
161
    def _check_revisions(self, inv):
164
162
        """Extension point for subclasses to check during serialisation.
165
163
 
171
169
        if inv.root.revision is None:
172
170
            raise AssertionError()
173
171
 
174
 
    def _check_cache_size(self, inv_size):
175
 
        """Check that the _entry_cache is large enough.
 
172
    def _check_cache_size(self, inv_size, entry_cache):
 
173
        """Check that the entry_cache is large enough.
176
174
 
177
175
        We want the cache to be ~2x the size of an inventory. The reason is
178
176
        because we use a FIFO cache, and how Inventory records are likely to
189
187
 
190
188
        :param inv_size: The number of entries in an inventory.
191
189
        """
 
190
        if entry_cache is None:
 
191
            return
192
192
        # 1.5 times might also be reasonable.
193
 
        recommended_cache_size = inv_size * 2
194
 
        if self._entry_cache.cache_size() < recommended_cache_size:
195
 
            trace.mutter('Resizing the inventory entry cache to %d',
196
 
                         recommended_cache_size)
197
 
            self._entry_cache.resize(recommended_cache_size)
 
193
        recommended_min_cache_size = inv_size * 1.5
 
194
        if entry_cache.cache_size() < recommended_min_cache_size:
 
195
            recommended_cache_size = inv_size * 2
 
196
            trace.mutter('Resizing the inventory entry cache from %d to %d',
 
197
                         entry_cache.cache_size(), recommended_cache_size)
 
198
            entry_cache.resize(recommended_cache_size)
198
199
 
199
200
    def write_inventory_to_lines(self, inv):
200
201
        """Return a list of lines with the encoded inventory."""
367
368
            prop_elt.tail = '\n'
368
369
        top_elt.tail = '\n'
369
370
 
370
 
    def _unpack_inventory(self, elt, revision_id=None):
 
371
    def _unpack_inventory(self, elt, revision_id=None, entry_cache=None):
371
372
        """Construct from XML Element"""
372
373
        if elt.tag != 'inventory':
373
374
            raise errors.UnexpectedInventoryFormat('Root tag is %r' % elt.tag)
375
376
        if format != self.format_num:
376
377
            raise errors.UnexpectedInventoryFormat('Invalid format version %r'
377
378
                                                   % format)
 
379
        if entry_cache is None:
 
380
            entry_cache = _entry_cache
378
381
        revision_id = elt.get('revision_id')
379
382
        if revision_id is not None:
380
383
            revision_id = cache_utf8.encode(revision_id)
381
384
        inv = inventory.Inventory(root_id=None, revision_id=revision_id)
382
385
        for e in elt:
383
 
            ie = self._unpack_entry(e)
 
386
            ie = self._unpack_entry(e, entry_cache=entry_cache)
384
387
            inv.add(ie)
385
 
        self._check_cache_size(len(inv))
 
388
        self._check_cache_size(len(inv), entry_cache)
386
389
        return inv
387
390
 
388
 
    def _unpack_entry(self, elt):
 
391
    def _unpack_entry(self, elt, entry_cache=None):
389
392
        elt_get = elt.get
390
393
        file_id = elt_get('file_id')
391
394
        revision = elt_get('revision')
420
423
        #   0.3s    cache miss lookus
421
424
        #   1.2s    decoding entries
422
425
        #   1.0s    adding nodes to LRU
423
 
        key = (file_id, revision)
424
 
        try:
425
 
            # We copy it, because some operatations may mutate it
426
 
            cached_ie = self._entry_cache[key]
427
 
        except KeyError:
428
 
            pass
429
 
        else:
430
 
            # Only copying directory entries drops us 2.85s => 2.35s
431
 
            # if cached_ie.kind == 'directory':
432
 
            #     return cached_ie.copy()
433
 
            # return cached_ie
434
 
            return cached_ie.copy()
 
426
        if entry_cache is not None and revision is not None:
 
427
            key = (file_id, revision)
 
428
            try:
 
429
                # We copy it, because some operatations may mutate it
 
430
                cached_ie = entry_cache[key]
 
431
            except KeyError:
 
432
                pass
 
433
            else:
 
434
                # Only copying directory entries drops us 2.85s => 2.35s
 
435
                # if cached_ie.kind == 'directory':
 
436
                #     return cached_ie.copy()
 
437
                # return cached_ie
 
438
                return cached_ie.copy()
435
439
 
436
440
        kind = elt.tag
437
441
        if not InventoryEntry.versionable_kind(kind):
467
471
        else:
468
472
            raise errors.UnsupportedInventoryKind(kind)
469
473
        ie.revision = revision
470
 
        if revision is not None:
 
474
        if revision is not None and entry_cache is not None:
471
475
            # We cache a copy() because callers like to mutate objects, and
472
476
            # that would cause the item in cache to mutate as well.
473
477
            # This has a small effect on many-inventory performance, because
474
478
            # the majority fraction is spent in cache hits, not misses.
475
 
            self._entry_cache[key] = ie.copy()
 
479
            entry_cache[key] = ie.copy()
476
480
 
477
481
        return ie
478
482