/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

Add a new method ``Tree.revision_tree`` which allows access to cached
trees for arbitrary revisions. This allows the in development dirstate
tree format to provide access to the callers to cached copies of 
inventory data which are cheaper to access than inventories from the
repository. (Robert Collins, Martin Pool)

Show diffs side-by-side

added added

removed removed

Lines of Context:
279
279
    stored and retrieved.
280
280
    """
281
281
 
282
 
    def __init__(self, relpath, transport, file_mode=None, access_mode=None, 
 
282
    def __init__(self, relpath, transport, file_mode=None, access_mode=None,
283
283
                 factory=None, basis_knit=DEPRECATED_PARAMETER, delta=True,
284
 
                 create=False):
 
284
                 create=False, create_parent_dir=False, delay_create=False,
 
285
                 dir_mode=None):
285
286
        """Construct a knit at location specified by relpath.
286
287
        
287
288
        :param create: If not True, only open an existing knit.
 
289
        :param create_parent_dir: If True, create the parent directory if 
 
290
            creating the file fails. (This is used for stores with 
 
291
            hash-prefixes that may not exist yet)
 
292
        :param delay_create: The calling code is aware that the knit won't 
 
293
            actually be created until the first data is stored.
288
294
        """
289
295
        if deprecated_passed(basis_knit):
290
296
            warnings.warn("KnitVersionedFile.__(): The basis_knit parameter is"
301
307
        self.delta = delta
302
308
 
303
309
        self._index = _KnitIndex(transport, relpath + INDEX_SUFFIX,
304
 
            access_mode, create=create, file_mode=file_mode)
 
310
            access_mode, create=create, file_mode=file_mode,
 
311
            create_parent_dir=create_parent_dir, delay_create=delay_create,
 
312
            dir_mode=dir_mode)
305
313
        self._data = _KnitData(transport, relpath + DATA_SUFFIX,
306
 
            access_mode, create=create and not len(self), file_mode=file_mode)
 
314
            access_mode, create=create and not len(self), file_mode=file_mode,
 
315
            create_parent_dir=create_parent_dir, delay_create=delay_create,
 
316
            dir_mode=dir_mode)
307
317
 
308
318
    def __repr__(self):
309
319
        return '%s(%s)' % (self.__class__.__name__, 
403
413
        """See VersionedFile.copy_to()."""
404
414
        # copy the current index to a temp index to avoid racing with local
405
415
        # writes
406
 
        transport.put(name + INDEX_SUFFIX + '.tmp', self.transport.get(self._index._filename),)
 
416
        transport.put_file_non_atomic(name + INDEX_SUFFIX + '.tmp',
 
417
                self.transport.get(self._index._filename))
407
418
        # copy the data file
408
419
        f = self._data._open_file()
409
420
        try:
410
 
            transport.put(name + DATA_SUFFIX, f)
 
421
            transport.put_file(name + DATA_SUFFIX, f)
411
422
        finally:
412
423
            f.close()
413
424
        # move the copied index into place
414
425
        transport.move(name + INDEX_SUFFIX + '.tmp', name + INDEX_SUFFIX)
415
426
 
416
427
    def create_empty(self, name, transport, mode=None):
417
 
        return KnitVersionedFile(name, transport, factory=self.factory, delta=self.delta, create=True)
 
428
        return KnitVersionedFile(name, transport, factory=self.factory,
 
429
                                 delta=self.delta, create=True)
418
430
    
419
431
    def _fix_parents(self, version, new_parents):
420
432
        """Fix the parents list for version.
946
958
class _KnitComponentFile(object):
947
959
    """One of the files used to implement a knit database"""
948
960
 
949
 
    def __init__(self, transport, filename, mode, file_mode=None):
 
961
    def __init__(self, transport, filename, mode, file_mode=None,
 
962
                 create_parent_dir=False, dir_mode=None):
950
963
        self._transport = transport
951
964
        self._filename = filename
952
965
        self._mode = mode
953
 
        self._file_mode=file_mode
954
 
 
955
 
    def write_header(self):
956
 
        if self._transport.append(self._filename, StringIO(self.HEADER),
957
 
            mode=self._file_mode):
958
 
            raise KnitCorrupt(self._filename, 'misaligned after writing header')
 
966
        self._file_mode = file_mode
 
967
        self._dir_mode = dir_mode
 
968
        self._create_parent_dir = create_parent_dir
 
969
        self._need_to_create = False
959
970
 
960
971
    def check_header(self, fp):
961
972
        line = fp.readline()
1048
1059
                                   parents,
1049
1060
                                   index)
1050
1061
 
1051
 
    def __init__(self, transport, filename, mode, create=False, file_mode=None):
1052
 
        _KnitComponentFile.__init__(self, transport, filename, mode, file_mode)
 
1062
    def __init__(self, transport, filename, mode, create=False, file_mode=None,
 
1063
                 create_parent_dir=False, delay_create=False, dir_mode=None):
 
1064
        _KnitComponentFile.__init__(self, transport, filename, mode,
 
1065
                                    file_mode=file_mode,
 
1066
                                    create_parent_dir=create_parent_dir,
 
1067
                                    dir_mode=dir_mode)
1053
1068
        self._cache = {}
1054
1069
        # position in _history is the 'official' index for a revision
1055
1070
        # but the values may have come from a newer entry.
1124
1139
            except NoSuchFile, e:
1125
1140
                if mode != 'w' or not create:
1126
1141
                    raise
1127
 
                self.write_header()
 
1142
                if delay_create:
 
1143
                    self._need_to_create = True
 
1144
                else:
 
1145
                    self._transport.put_bytes_non_atomic(self._filename,
 
1146
                        self.HEADER, mode=self._file_mode)
 
1147
 
1128
1148
        finally:
1129
1149
            pb.update('read knit index', total, total)
1130
1150
            pb.finished()
1245
1265
            assert isinstance(line, str), \
1246
1266
                'content must be utf-8 encoded: %r' % (line,)
1247
1267
            lines.append(line)
1248
 
        self._transport.append(self._filename, StringIO(''.join(lines)))
 
1268
        if not self._need_to_create:
 
1269
            self._transport.append_bytes(self._filename, ''.join(lines))
 
1270
        else:
 
1271
            sio = StringIO()
 
1272
            sio.write(self.HEADER)
 
1273
            sio.writelines(lines)
 
1274
            sio.seek(0)
 
1275
            self._transport.put_file_non_atomic(self._filename, sio,
 
1276
                                create_parent_dir=self._create_parent_dir,
 
1277
                                mode=self._file_mode,
 
1278
                                dir_mode=self._dir_mode)
 
1279
            self._need_to_create = False
 
1280
 
1249
1281
        # cache after writing, so that a failed write leads to missing cache
1250
1282
        # entries not extra ones. XXX TODO: RBC 20060502 in the event of a 
1251
1283
        # failure, reload the index or flush it or some such, to prevent
1296
1328
class _KnitData(_KnitComponentFile):
1297
1329
    """Contents of the knit data file"""
1298
1330
 
1299
 
    HEADER = "# bzr knit data 8\n"
1300
 
 
1301
 
    def __init__(self, transport, filename, mode, create=False, file_mode=None):
1302
 
        _KnitComponentFile.__init__(self, transport, filename, mode)
 
1331
    def __init__(self, transport, filename, mode, create=False, file_mode=None,
 
1332
                 create_parent_dir=False, delay_create=False,
 
1333
                 dir_mode=None):
 
1334
        _KnitComponentFile.__init__(self, transport, filename, mode,
 
1335
                                    file_mode=file_mode,
 
1336
                                    create_parent_dir=create_parent_dir,
 
1337
                                    dir_mode=dir_mode)
1303
1338
        self._checked = False
1304
1339
        # TODO: jam 20060713 conceptually, this could spill to disk
1305
1340
        #       if the cached size gets larger than a certain amount
1308
1343
        self._cache = {}
1309
1344
        self._do_cache = False
1310
1345
        if create:
1311
 
            self._transport.put(self._filename, StringIO(''), mode=file_mode)
 
1346
            if delay_create:
 
1347
                self._need_to_create = create
 
1348
            else:
 
1349
                self._transport.put_bytes_non_atomic(self._filename, '',
 
1350
                                                     mode=self._file_mode)
1312
1351
 
1313
1352
    def enable_cache(self):
1314
1353
        """Enable caching of reads."""
1353
1392
        :return: the offset in the data file raw_data was written.
1354
1393
        """
1355
1394
        assert isinstance(raw_data, str), 'data must be plain bytes'
1356
 
        return self._transport.append(self._filename, StringIO(raw_data))
 
1395
        if not self._need_to_create:
 
1396
            return self._transport.append_bytes(self._filename, raw_data)
 
1397
        else:
 
1398
            self._transport.put_bytes_non_atomic(self._filename, raw_data,
 
1399
                                   create_parent_dir=self._create_parent_dir,
 
1400
                                   mode=self._file_mode,
 
1401
                                   dir_mode=self._dir_mode)
 
1402
            self._need_to_create = False
 
1403
            return 0
1357
1404
        
1358
1405
    def add_record(self, version_id, digest, lines):
1359
1406
        """Write new text record to disk.  Returns the position in the
1360
1407
        file where it was written."""
1361
1408
        size, sio = self._record_to_data(version_id, digest, lines)
1362
1409
        # write to disk
1363
 
        start_pos = self._transport.append(self._filename, sio)
 
1410
        if not self._need_to_create:
 
1411
            start_pos = self._transport.append_file(self._filename, sio)
 
1412
        else:
 
1413
            self._transport.put_file_non_atomic(self._filename, sio,
 
1414
                               create_parent_dir=self._create_parent_dir,
 
1415
                               mode=self._file_mode,
 
1416
                               dir_mode=self._dir_mode)
 
1417
            self._need_to_create = False
 
1418
            start_pos = 0
1364
1419
        if self._do_cache:
1365
1420
            self._cache[version_id] = sio.getvalue()
1366
1421
        return start_pos, size