~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/upgrade.py

  • Committer: Martin Pool
  • Date: 2005-09-23 03:12:43 UTC
  • Revision ID: mbp@sourcefrog.net-20050923031242-4e2d76a5bf5a4b1c
- avoiding loading all inventories upfront for conversion
  uses too much memory on large trees

Show diffs side-by-side

added added

removed removed

Lines of Context:
78
78
 
79
79
import os
80
80
import tempfile
81
 
import hotshot, hotshot.stats
82
81
import sys
83
82
import logging
84
83
import shutil
103
102
        self.absent_revisions = set()
104
103
        self.text_count = 0
105
104
        self.revisions = {}
106
 
        self.inventories = {}
107
105
        self.convert()
108
106
 
109
107
 
110
108
    def convert(self):
111
109
        if not self._open_branch():
112
110
            return
113
 
        note('starting upgrade of %s', self.base)
 
111
        note('starting upgrade of %s', os.path.abspath(self.base))
114
112
        self._backup_control_dir()
115
113
        note('starting upgrade')
116
114
        note('note: upgrade may be faster if all store files are ungzipped first')
183
181
    def _backup_control_dir(self):
184
182
        orig = self.base + '/.bzr'
185
183
        backup = orig + '.backup'
 
184
        note('making backup of tree history')
186
185
        shutil.copytree(orig, backup)
187
186
        note('%s has been backed up to %s', orig, backup)
188
187
        note('if conversion fails, you can move this directory back to .bzr')
246
245
                self.known_revisions.add(parent_id)
247
246
                self.to_read.append(parent_id)
248
247
            self.revisions[rev_id] = rev
249
 
            old_inv_xml = self.branch.inventory_store[rev_id].read()
250
 
            inv = serializer_v4.read_inventory_from_string(old_inv_xml)
251
 
            assert rev.inventory_sha1 == sha_string(old_inv_xml)
252
 
            self.inventories[rev_id] = inv
 
248
 
 
249
 
 
250
    def _load_old_inventory(self, rev_id):
 
251
        assert rev_id not in self.converted_revs
 
252
        old_inv_xml = self.branch.inventory_store[rev_id].read()
 
253
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
 
254
        rev = self.revisions[rev_id]
 
255
        if rev.inventory_sha1:
 
256
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
 
257
                'inventory sha mismatch for {%s}' % rev_id
 
258
        return inv
253
259
        
254
260
 
 
261
    def _load_updated_inventory(self, rev_id):
 
262
        assert rev_id in self.converted_revs
 
263
        inv_xml = self.inv_weave.get_text(rev_id)
 
264
        inv = serializer_v5.read_inventory_from_string(inv_xml)
 
265
        return inv
 
266
 
 
267
 
255
268
    def _convert_one_rev(self, rev_id):
256
269
        """Convert revision and all referenced objects to new format."""
257
270
        rev = self.revisions[rev_id]
258
 
        inv = self.inventories[rev_id]
 
271
        inv = self._load_old_inventory(rev_id)
259
272
        for parent_id in rev.parent_ids[:]:
260
273
            if parent_id in self.absent_revisions:
261
274
                rev.parent_ids.remove(parent_id)
262
275
                self.pb.clear()
263
276
                note('remove {%s} as parent of {%s}', parent_id, rev_id)
264
277
        self._convert_revision_contents(rev, inv)
 
278
        self._store_new_weave(rev, inv)
 
279
        self._make_rev_ancestry(rev)
 
280
        self.converted_revs.add(rev_id)
 
281
 
 
282
 
 
283
    def _store_new_weave(self, rev, inv):
265
284
        # the XML is now updated with text versions
 
285
        if __debug__:
 
286
            for file_id in inv:
 
287
                ie = inv[file_id]
 
288
                if ie.kind == 'root_directory':
 
289
                    continue
 
290
                assert hasattr(ie, 'name_version'), \
 
291
                    'no name_version on {%s} in {%s}' % \
 
292
                    (file_id, rev.revision_id)
 
293
                if ie.kind == 'file':
 
294
                    assert hasattr(ie, 'text_version')
 
295
 
266
296
        new_inv_xml = serializer_v5.write_inventory_to_string(inv)
267
297
        new_inv_sha1 = sha_string(new_inv_xml)
268
 
        self.inv_weave.add(rev_id, rev.parent_ids,
 
298
        self.inv_weave.add(rev.revision_id, rev.parent_ids,
269
299
                           new_inv_xml.splitlines(True),
270
300
                           new_inv_sha1)
271
 
        # TODO: Upgrade revision XML and write that out
272
301
        rev.inventory_sha1 = new_inv_sha1
273
 
        self._make_rev_ancestry(rev)
274
 
        self.converted_revs.add(rev_id)
275
302
 
276
303
 
277
304
    def _make_rev_ancestry(self, rev):
298
325
        rev_id = rev.revision_id
299
326
        mutter('converting texts of revision {%s}',
300
327
               rev_id)
 
328
        parent_invs = map(self._load_updated_inventory, rev.parent_ids)
301
329
        for file_id in inv:
302
330
            ie = inv[file_id]
303
 
            self._set_name_version(rev, ie)
 
331
            self._set_name_version(rev, ie, parent_invs)
304
332
            if ie.kind != 'file':
305
333
                continue
306
 
            self._convert_file_version(rev, ie)
307
 
 
308
 
 
309
 
    def _set_name_version(self, rev, ie):
 
334
            self._convert_file_version(rev, ie, parent_invs)
 
335
 
 
336
 
 
337
    def _set_name_version(self, rev, ie, parent_invs):
310
338
        """Set name version for a file.
311
339
 
312
340
        Done in a slightly lazy way: if the file is renamed or in a merge revision
313
341
        it gets a new version, otherwise the same as before.
314
342
        """
315
343
        file_id = ie.file_id
316
 
        if len(rev.parent_ids) != 1:
 
344
        if ie.kind == 'root_directory':
 
345
            return
 
346
        if len(parent_invs) != 1:
317
347
            ie.name_version = rev.revision_id
318
348
        else:
319
 
            old_inv = self.inventories[rev.parent_ids[0]]
 
349
            old_inv = parent_invs[0]
320
350
            if not old_inv.has_id(file_id):
321
351
                ie.name_version = rev.revision_id
322
352
            else:
323
353
                old_ie = old_inv[file_id]
 
354
                import pdb
 
355
                # pdb.set_trace()
324
356
                if (old_ie.parent_id != ie.parent_id
325
357
                    or old_ie.name != ie.name):
326
358
                    ie.name_version = rev.revision_id
329
361
 
330
362
 
331
363
 
332
 
    def _convert_file_version(self, rev, ie):
 
364
    def _convert_file_version(self, rev, ie, parent_invs):
333
365
        """Convert one version of one file.
334
366
 
335
367
        The file needs to be added into the weave if it is a merge
343
375
            self.text_weaves[file_id] = w
344
376
        file_parents = []
345
377
        text_changed = False
346
 
        for parent_id in rev.parent_ids:
347
 
            ##if parent_id in self.absent_revisions:
348
 
            ##    continue
349
 
            assert parent_id in self.converted_revs, \
350
 
                   'parent {%s} not converted' % parent_id
351
 
            parent_inv = self.inventories[parent_id]
 
378
        for parent_inv in parent_invs:
352
379
            if parent_inv.has_id(file_id):
353
380
                parent_ie = parent_inv[file_id]
354
381
                old_text_version = parent_ie.text_version