~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/_groupcompress_pyx.pyx

  • Committer: Danny van Heumen
  • Date: 2010-03-09 21:42:11 UTC
  • mto: (4634.139.5 2.0)
  • mto: This revision was merged to the branch mainline in revision 5160.
  • Revision ID: danny@dannyvanheumen.nl-20100309214211-iqh42x6qcikgd9p3
Reverted now-useless TODO list.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2008, 2009, 2010 Canonical Ltd
 
1
# Copyright (C) 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
22
22
 
23
23
 
24
24
cdef extern from "Python.h":
25
 
    ctypedef struct PyObject:
26
 
        pass
27
25
    ctypedef int Py_ssize_t # Required for older pyrex versions
28
26
    int PyString_CheckExact(object)
29
27
    char * PyString_AS_STRING(object)
33
31
 
34
32
cdef extern from *:
35
33
    ctypedef unsigned long size_t
36
 
    void * malloc(size_t) nogil
37
 
    void * realloc(void *, size_t) nogil
38
 
    void free(void *) nogil
39
 
    void memcpy(void *, void *, size_t) nogil
 
34
    void * malloc(size_t)
 
35
    void * realloc(void *, size_t)
 
36
    void free(void *)
 
37
    void memcpy(void *, void *, size_t)
40
38
 
41
39
 
42
40
cdef extern from "delta.h":
46
44
        unsigned long agg_offset
47
45
    struct delta_index:
48
46
        pass
49
 
    delta_index * create_delta_index(source_info *src, delta_index *old) nogil
 
47
    delta_index * create_delta_index(source_info *src, delta_index *old)
50
48
    delta_index * create_delta_index_from_delta(source_info *delta,
51
 
                                                delta_index *old) nogil
52
 
    void free_delta_index(delta_index *index) nogil
 
49
                                                delta_index *old)
 
50
    void free_delta_index(delta_index *index)
53
51
    void *create_delta(delta_index *indexes,
54
52
             void *buf, unsigned long bufsize,
55
 
             unsigned long *delta_size, unsigned long max_delta_size) nogil
 
53
             unsigned long *delta_size, unsigned long max_delta_size)
56
54
    unsigned long get_delta_hdr_size(unsigned char **datap,
57
 
                                     unsigned char *top) nogil
58
 
    unsigned long sizeof_delta_index(delta_index *index)
 
55
                                     unsigned char *top)
59
56
    Py_ssize_t DELTA_SIZE_MIN
 
57
    void *patch_delta(void *src_buf, unsigned long src_size,
 
58
                      void *delta_buf, unsigned long delta_size,
 
59
                      unsigned long *dst_size)
60
60
 
61
61
 
62
62
cdef void *safe_malloc(size_t count) except NULL:
94
94
    cdef readonly object _sources
95
95
    cdef source_info *_source_infos
96
96
    cdef delta_index *_index
 
97
    cdef readonly unsigned int _max_num_sources
97
98
    cdef public unsigned long _source_offset
98
 
    cdef readonly unsigned int _max_num_sources
99
99
 
100
100
    def __init__(self, source=None):
101
101
        self._sources = []
108
108
        if source is not None:
109
109
            self.add_source(source, 0)
110
110
 
111
 
    def __sizeof__(self):
112
 
        # We want to track the _source_infos allocations, but the referenced
113
 
        # void* are actually tracked in _sources itself.
114
 
        # XXX: Cython is capable of doing sizeof(class) and returning the size
115
 
        #      of the underlying struct. Pyrex (<= 0.9.9) refuses, so we need
116
 
        #      to do it manually. *sigh* Note that we might get it wrong
117
 
        #      because of alignment issues.
118
 
        cdef Py_ssize_t size
119
 
        # PyObject start, vtable *, 3 object pointers, 2 C ints
120
 
        size = ((sizeof(PyObject) + sizeof(void*) + 3*sizeof(PyObject*)
121
 
                 + sizeof(unsigned long)
122
 
                 + sizeof(unsigned int))
123
 
                + (sizeof(source_info) * self._max_num_sources)
124
 
                + sizeof_delta_index(self._index))
125
 
        return size
126
 
 
127
111
    def __repr__(self):
128
112
        return '%s(%d, %d)' % (self.__class__.__name__,
129
113
            len(self._sources), self._source_offset)
164
148
        src.buf = c_delta
165
149
        src.size = c_delta_size
166
150
        src.agg_offset = self._source_offset + unadded_bytes
167
 
        with nogil:
168
 
            index = create_delta_index_from_delta(src, self._index)
 
151
        index = create_delta_index_from_delta(src, self._index)
169
152
        self._source_offset = src.agg_offset + src.size
170
153
        if index != NULL:
171
154
            free_delta_index(self._index)
205
188
        self._source_offset = src.agg_offset + src.size
206
189
        # We delay creating the index on the first insert
207
190
        if source_location != 0:
208
 
            with nogil:
209
 
                index = create_delta_index(src, self._index)
 
191
            index = create_delta_index(src, self._index)
210
192
            if index != NULL:
211
193
                free_delta_index(self._index)
212
194
                self._index = index
219
201
 
220
202
        # We know that self._index is already NULL, so whatever
221
203
        # create_delta_index returns is fine
222
 
        with nogil:
223
 
            self._index = create_delta_index(&self._source_infos[0], NULL)
 
204
        self._index = create_delta_index(&self._source_infos[0], NULL)
224
205
        assert self._index != NULL
225
206
 
226
207
    cdef _expand_sources(self):
237
218
        cdef Py_ssize_t target_size
238
219
        cdef void * delta
239
220
        cdef unsigned long delta_size
240
 
        cdef unsigned long c_max_delta_size
241
221
 
242
222
        if self._index == NULL:
243
223
            if len(self._sources) == 0:
254
234
        # TODO: inline some of create_delta so we at least don't have to double
255
235
        #       malloc, and can instead use PyString_FromStringAndSize, to
256
236
        #       allocate the bytes into the final string
257
 
        c_max_delta_size = max_delta_size
258
 
        with nogil:
259
 
            delta = create_delta(self._index,
260
 
                                 target, target_size,
261
 
                                 &delta_size, c_max_delta_size)
 
237
        delta = create_delta(self._index,
 
238
                             target, target_size,
 
239
                             &delta_size, max_delta_size)
262
240
        result = None
263
241
        if delta:
264
242
            result = PyString_FromStringAndSize(<char *>delta, delta_size)
298
276
 
299
277
 
300
278
cdef unsigned char *_decode_copy_instruction(unsigned char *bytes,
301
 
    unsigned char cmd, unsigned int *offset,
302
 
    unsigned int *length) nogil: # cannot_raise
 
279
    unsigned char cmd, unsigned int *offset, unsigned int *length): # cannot_raise
303
280
    """Decode a copy instruction from the next few bytes.
304
281
 
305
282
    A copy instruction is a variable number of bytes, so we will parse the
349
326
    cdef unsigned char *dst_buf, *out, cmd
350
327
    cdef Py_ssize_t size
351
328
    cdef unsigned int cp_off, cp_size
352
 
    cdef int failed
353
329
 
354
330
    data = <unsigned char *>delta
355
331
    top = data + delta_size
359
335
    result = PyString_FromStringAndSize(NULL, size)
360
336
    dst_buf = <unsigned char*>PyString_AS_STRING(result)
361
337
 
362
 
    failed = 0
363
 
    with nogil:
364
 
        out = dst_buf
365
 
        while (data < top):
366
 
            cmd = data[0]
367
 
            data = data + 1
368
 
            if (cmd & 0x80):
369
 
                # Copy instruction
370
 
                data = _decode_copy_instruction(data, cmd, &cp_off, &cp_size)
371
 
                if (cp_off + cp_size < cp_size or
372
 
                    cp_off + cp_size > source_size or
373
 
                    cp_size > size):
374
 
                    failed = 1
375
 
                    break
376
 
                memcpy(out, source + cp_off, cp_size)
377
 
                out = out + cp_size
378
 
                size = size - cp_size
379
 
            else:
380
 
                # Insert instruction
381
 
                if cmd == 0:
382
 
                    # cmd == 0 is reserved for future encoding
383
 
                    # extensions. In the mean time we must fail when
384
 
                    # encountering them (might be data corruption).
385
 
                    failed = 2
386
 
                    break
387
 
                if cmd > size:
388
 
                    failed = 3
389
 
                    break
390
 
                memcpy(out, data, cmd)
391
 
                out = out + cmd
392
 
                data = data + cmd
393
 
                size = size - cmd
394
 
    if failed:
395
 
        if failed == 1:
396
 
            raise ValueError('Something wrong with:'
397
 
                ' cp_off = %s, cp_size = %s'
398
 
                ' source_size = %s, size = %s'
399
 
                % (cp_off, cp_size, source_size, size))
400
 
        elif failed == 2:
401
 
            raise ValueError('Got delta opcode: 0, not supported')
402
 
        elif failed == 3:
403
 
            raise ValueError('Insert instruction longer than remaining'
404
 
                ' bytes: %d > %d' % (cmd, size))
 
338
    out = dst_buf
 
339
    while (data < top):
 
340
        cmd = data[0]
 
341
        data = data + 1
 
342
        if (cmd & 0x80):
 
343
            # Copy instruction
 
344
            data = _decode_copy_instruction(data, cmd, &cp_off, &cp_size)
 
345
            if (cp_off + cp_size < cp_size or
 
346
                cp_off + cp_size > source_size or
 
347
                cp_size > size):
 
348
                raise RuntimeError('Something wrong with:'
 
349
                    ' cp_off = %s, cp_size = %s'
 
350
                    ' source_size = %s, size = %s'
 
351
                    % (cp_off, cp_size, source_size, size))
 
352
            memcpy(out, source + cp_off, cp_size)
 
353
            out = out + cp_size
 
354
            size = size - cp_size
 
355
        else:
 
356
            # Insert instruction
 
357
            if cmd == 0:
 
358
                # cmd == 0 is reserved for future encoding
 
359
                # extensions. In the mean time we must fail when
 
360
                # encountering them (might be data corruption).
 
361
                raise RuntimeError('Got delta opcode: 0, not supported')
 
362
            if (cmd > size):
 
363
                raise RuntimeError('Insert instruction longer than remaining'
 
364
                    ' bytes: %d > %d' % (cmd, size))
 
365
            memcpy(out, data, cmd)
 
366
            out = out + cmd
 
367
            data = data + cmd
 
368
            size = size - cmd
405
369
 
406
370
    # sanity check
407
371
    if (data != top or size != 0):