~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tuned_gzip.py

  • Committer: Martin Pool
  • Date: 2009-01-13 03:11:04 UTC
  • mto: This revision was merged to the branch mainline in revision 3937.
  • Revision ID: mbp@sourcefrog.net-20090113031104-03my054s02i9l2pe
Bump version to 1.12 and add news template

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
#
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
18
18
"""Bzrlib specific gzip tunings. We plan to feed these to the upstream gzip."""
19
19
 
52
52
    width=-zlib.MAX_WBITS, mem=zlib.DEF_MEM_LEVEL,
53
53
    crc32=zlib.crc32):
54
54
    """Create a gzip file containing bytes and return its content."""
55
 
    return chunks_to_gzip([bytes])
56
 
 
57
 
 
58
 
def chunks_to_gzip(chunks, factory=zlib.compressobj,
59
 
    level=zlib.Z_DEFAULT_COMPRESSION, method=zlib.DEFLATED,
60
 
    width=-zlib.MAX_WBITS, mem=zlib.DEF_MEM_LEVEL,
61
 
    crc32=zlib.crc32):
62
 
    """Create a gzip file containing chunks and return its content.
63
 
 
64
 
    :param chunks: An iterable of strings. Each string can have arbitrary
65
 
        layout.
66
 
    """
67
55
    result = [
68
56
        '\037\213'  # self.fileobj.write('\037\213')  # magic header
69
57
        '\010'      # self.fileobj.write('\010')      # compression method
81
69
    # using a compressobj avoids a small header and trailer that the compress()
82
70
    # utility function adds.
83
71
    compress = factory(level, method, width, mem, 0)
84
 
    crc = 0
85
 
    total_len = 0
86
 
    for chunk in chunks:
87
 
        crc = crc32(chunk, crc)
88
 
        total_len += len(chunk)
89
 
        zbytes = compress.compress(chunk)
90
 
        if zbytes:
91
 
            result.append(zbytes)
 
72
    result.append(compress.compress(bytes))
92
73
    result.append(compress.flush())
 
74
    result.append(struct.pack("<L", LOWU32(crc32(bytes))))
93
75
    # size may exceed 2GB, or even 4GB
94
 
    result.append(struct.pack("<LL", LOWU32(crc), LOWU32(total_len)))
 
76
    result.append(struct.pack("<L", LOWU32(len(bytes))))
95
77
    return ''.join(result)
96
78
 
97
79
 
132
114
        """A tuned version of gzip._write_gzip_header
133
115
 
134
116
        We have some extra constrains that plain Gzip does not.
135
 
        1) We want to write the whole blob at once. rather than multiple
 
117
        1) We want to write the whole blob at once. rather than multiple 
136
118
           calls to fileobj.write().
137
119
        2) We never have a filename
138
120
        3) We don't care about the time
154
136
 
155
137
    def _read(self, size=1024):
156
138
        # various optimisations:
157
 
        # reduces lsprof count from 2500 to
 
139
        # reduces lsprof count from 2500 to 
158
140
        # 8337 calls in 1272, 365 internal
159
141
        if self.fileobj is None:
160
142
            raise EOFError, "Reached EOF"
225
207
        """tuned to reduce function calls and eliminate file seeking:
226
208
        pass 1:
227
209
        reduces lsprof count from 800 to 288
228
 
        4168 in 296
 
210
        4168 in 296 
229
211
        avoid U32 call by using struct format L
230
212
        4168 in 200
231
213
        """
232
 
        # We've read to the end of the file, so we should have 8 bytes of
 
214
        # We've read to the end of the file, so we should have 8 bytes of 
233
215
        # unused data in the decompressor. If we don't, there is a corrupt file.
234
216
        # We use these 8 bytes to calculate the CRC and the recorded file size.
235
217
        # We then check the that the computed CRC and size of the
246
228
 
247
229
    def _read_gzip_header(self, bytes=None):
248
230
        """Supply bytes if the minimum header size is already read.
249
 
 
 
231
        
250
232
        :param bytes: 10 bytes of header data.
251
233
        """
252
234
        """starting cost: 300 in 3998
289
271
 
290
272
    def readline(self, size=-1):
291
273
        """Tuned to remove buffer length calls in _unread and...
292
 
 
 
274
        
293
275
        also removes multiple len(c) calls, inlines _unread,
294
276
        total savings - lsprof 5800 to 5300
295
277
        phase 2:
299
281
        leading to a drop to:
300
282
        4168 calls in 1977
301
283
        4168 call to read() in 1646
302
 
        - i.e. just reduced the function call overhead. May be worth
 
284
        - i.e. just reduced the function call overhead. May be worth 
303
285
          keeping.
304
286
        """
305
287
        if size < 0: size = sys.maxint
347
329
        # to :
348
330
        # 4168 calls in 417.
349
331
        # Negative numbers result in reading all the lines
350
 
 
 
332
        
351
333
        # python's gzip routine uses sizehint. This is a more efficient way
352
334
        # than python uses to honor it. But it is even more efficient to
353
335
        # just read the entire thing and use cStringIO to split into lines.
360
342
 
361
343
    def _unread(self, buf, len_buf=None):
362
344
        """tuned to remove unneeded len calls.
363
 
 
 
345
        
364
346
        because this is such an inner routine in readline, and readline is
365
347
        in many inner loops, this has been inlined into readline().
366
348
 
367
349
        The len_buf parameter combined with the reduction in len calls dropped
368
 
        the lsprof ms count for this routine on my test data from 800 to 200 -
 
350
        the lsprof ms count for this routine on my test data from 800 to 200 - 
369
351
        a 75% saving.
370
352
        """
371
353
        if len_buf is None:
389
371
            self.offset += data_len
390
372
 
391
373
    def writelines(self, lines):
392
 
        # profiling indicated a significant overhead
 
374
        # profiling indicated a significant overhead 
393
375
        # calling write for each line.
394
376
        # this batch call is a lot faster :).
395
377
        # (4 seconds to 1 seconds for the sample upgrades I was testing).