~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-09-06 22:55:29 UTC
  • mfrom: (1946.2.16 reduce-knit-churn)
  • Revision ID: pqm@pqm.ubuntu.com-20060906225529-7b367edabbb1ffc2
(jam) delay creating knit contents for significantly better new commit and push performance

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__, 
948
958
class _KnitComponentFile(object):
949
959
    """One of the files used to implement a knit database"""
950
960
 
951
 
    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):
952
963
        self._transport = transport
953
964
        self._filename = filename
954
965
        self._mode = mode
955
 
        self._file_mode=file_mode
956
 
 
957
 
    def write_header(self):
958
 
        if self._transport.put_bytes_non_atomic(self._filename, self.HEADER,
959
 
                mode=self._file_mode):
960
 
            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
961
970
 
962
971
    def check_header(self, fp):
963
972
        line = fp.readline()
1050
1059
                                   parents,
1051
1060
                                   index)
1052
1061
 
1053
 
    def __init__(self, transport, filename, mode, create=False, file_mode=None):
1054
 
        _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)
1055
1068
        self._cache = {}
1056
1069
        # position in _history is the 'official' index for a revision
1057
1070
        # but the values may have come from a newer entry.
1126
1139
            except NoSuchFile, e:
1127
1140
                if mode != 'w' or not create:
1128
1141
                    raise
1129
 
                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
 
1130
1148
        finally:
1131
1149
            pb.update('read knit index', total, total)
1132
1150
            pb.finished()
1247
1265
            assert isinstance(line, str), \
1248
1266
                'content must be utf-8 encoded: %r' % (line,)
1249
1267
            lines.append(line)
1250
 
        self._transport.append_bytes(self._filename, ''.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
 
1251
1281
        # cache after writing, so that a failed write leads to missing cache
1252
1282
        # entries not extra ones. XXX TODO: RBC 20060502 in the event of a 
1253
1283
        # failure, reload the index or flush it or some such, to prevent
1298
1328
class _KnitData(_KnitComponentFile):
1299
1329
    """Contents of the knit data file"""
1300
1330
 
1301
 
    HEADER = "# bzr knit data 8\n"
1302
 
 
1303
 
    def __init__(self, transport, filename, mode, create=False, file_mode=None):
1304
 
        _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)
1305
1338
        self._checked = False
1306
1339
        # TODO: jam 20060713 conceptually, this could spill to disk
1307
1340
        #       if the cached size gets larger than a certain amount
1310
1343
        self._cache = {}
1311
1344
        self._do_cache = False
1312
1345
        if create:
1313
 
            self._transport.put_bytes_non_atomic(self._filename, '',
1314
 
                                                 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)
1315
1351
 
1316
1352
    def enable_cache(self):
1317
1353
        """Enable caching of reads."""
1356
1392
        :return: the offset in the data file raw_data was written.
1357
1393
        """
1358
1394
        assert isinstance(raw_data, str), 'data must be plain bytes'
1359
 
        return self._transport.append_bytes(self._filename, 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
1360
1404
        
1361
1405
    def add_record(self, version_id, digest, lines):
1362
1406
        """Write new text record to disk.  Returns the position in the
1363
1407
        file where it was written."""
1364
1408
        size, sio = self._record_to_data(version_id, digest, lines)
1365
1409
        # write to disk
1366
 
        start_pos = self._transport.append_file(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
1367
1419
        if self._do_cache:
1368
1420
            self._cache[version_id] = sio.getvalue()
1369
1421
        return start_pos, size