~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/pack.py

  • Committer: Martin Pool
  • Date: 2011-11-29 09:13:54 UTC
  • mto: This revision was merged to the branch mainline in revision 6329.
  • Revision ID: mbp@canonical.com-20111129091354-zcwnzn3cy1jfzqju
ContainerWriter: Avoid one possible large-string join

Show diffs side-by-side

added added

removed removed

Lines of Context:
75
75
        """Return the bytes to finish a container."""
76
76
        return "E"
77
77
 
78
 
    def bytes_record(self, bytes, names):
79
 
        """Return the bytes for a Bytes record with the given name and
80
 
        contents.
81
 
        """
 
78
    def bytes_header(self, length, names):
 
79
        """Return the header for a Bytes record."""
82
80
        # Kind marker
83
81
        byte_sections = ["B"]
84
82
        # Length
85
 
        byte_sections.append(str(len(bytes)) + "\n")
 
83
        byte_sections.append(str(length) + "\n")
86
84
        # Names
87
85
        for name_tuple in names:
88
86
            # Make sure we're writing valid names.  Note that we will leave a
92
90
            byte_sections.append('\x00'.join(name_tuple) + "\n")
93
91
        # End of headers
94
92
        byte_sections.append("\n")
95
 
        # Finally, the contents.
96
 
        byte_sections.append(bytes)
97
 
        # XXX: This causes a memory copy of bytes in size, but is usually
98
 
        # faster than two write calls (12 vs 13 seconds to output a gig of
99
 
        # 1k records.) - results may differ on significantly larger records
100
 
        # like .iso's but as they should be rare in any case and thus not
101
 
        # likely to be the common case. The biggest issue is causing extreme
102
 
        # memory pressure in that case. One possibly improvement here is to
103
 
        # check the size of the content before deciding to join here vs call
104
 
        # write twice.
105
93
        return ''.join(byte_sections)
106
94
 
 
95
    def bytes_record(self, bytes, names):
 
96
        """Return the bytes for a Bytes record with the given name and
 
97
        contents.
 
98
 
 
99
        If the content may be large, construct the header separately and then
 
100
        stream out the contents.
 
101
        """
 
102
        return self.bytes_header(len(bytes), names) + bytes
 
103
 
107
104
 
108
105
class ContainerWriter(object):
109
106
    """A class for writing containers to a file.
113
110
        introduced by the begin() and end() methods.
114
111
    """
115
112
 
 
113
    # Join up headers with the body if writing fewer than this many bytes:
 
114
    # trades off memory usage and copying to do less IO ops.
 
115
    _JOIN_WRITES_THRESHOLD = 100000
 
116
 
116
117
    def __init__(self, write_func):
117
118
        """Constructor.
118
119
 
151
152
            and thus are only suitable for use by a ContainerReader.
152
153
        """
153
154
        current_offset = self.current_offset
154
 
        serialised_record = self._serialiser.bytes_record(bytes, names)
155
 
        self.write_func(serialised_record)
 
155
        length = len(bytes)
 
156
        if length < self._JOIN_WRITES_THRESHOLD:
 
157
            self.write_func(self._serialiser.bytes_header(length, names)
 
158
                + bytes)
 
159
        else:
 
160
            self.write_func(self._serialiser.bytes_header(length, names))
 
161
            self.write_func(bytes)
156
162
        self.records_written += 1
157
163
        # return a memo of where we wrote data to allow random access.
158
164
        return current_offset, self.current_offset - current_offset