/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/groupcompress.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-01-14 00:01:32 UTC
  • mfrom: (4957.1.1 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20100114000132-3p3rabnonjw3gzqb
(jam) Merge bzr.stable, bringing in bug fixes #175839, #504390

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
    knit,
32
32
    osutils,
33
33
    pack,
 
34
    static_tuple,
34
35
    trace,
35
36
    )
36
37
from bzrlib.btree_index import BTreeBuilder
119
120
        :param num_bytes: Ensure that we have extracted at least num_bytes of
120
121
            content. If None, consume everything
121
122
        """
122
 
        # TODO: If we re-use the same content block at different times during
123
 
        #       get_record_stream(), it is possible that the first pass will
124
 
        #       get inserted, triggering an extract/_ensure_content() which
125
 
        #       will get rid of _z_content. And then the next use of the block
126
 
        #       will try to access _z_content (to send it over the wire), and
127
 
        #       fail because it is already extracted. Consider never releasing
128
 
        #       _z_content because of this.
 
123
        if self._content_length is None:
 
124
            raise AssertionError('self._content_length should never be None')
129
125
        if num_bytes is None:
130
126
            num_bytes = self._content_length
131
127
        elif (self._content_length is not None
148
144
                self._content = pylzma.decompress(self._z_content)
149
145
            elif self._compressor_name == 'zlib':
150
146
                # Start a zlib decompressor
151
 
                if num_bytes is None:
 
147
                if num_bytes * 4 > self._content_length * 3:
 
148
                    # If we are requesting more that 3/4ths of the content,
 
149
                    # just extract the whole thing in a single pass
 
150
                    num_bytes = self._content_length
152
151
                    self._content = zlib.decompress(self._z_content)
153
152
                else:
154
153
                    self._z_content_decompressor = zlib.decompressobj()
156
155
                    # that the rest of the code is simplified
157
156
                    self._content = self._z_content_decompressor.decompress(
158
157
                        self._z_content, num_bytes + _ZLIB_DECOMP_WINDOW)
 
158
                    if not self._z_content_decompressor.unconsumed_tail:
 
159
                        self._z_content_decompressor = None
159
160
            else:
160
161
                raise AssertionError('Unknown compressor: %r'
161
162
                                     % self._compressor_name)
163
164
        # 'unconsumed_tail'
164
165
 
165
166
        # Do we have enough bytes already?
166
 
        if num_bytes is not None and len(self._content) >= num_bytes:
167
 
            return
168
 
        if num_bytes is None and self._z_content_decompressor is None:
169
 
            # We must have already decompressed everything
 
167
        if len(self._content) >= num_bytes:
170
168
            return
171
169
        # If we got this far, and don't have a decompressor, something is wrong
172
170
        if self._z_content_decompressor is None:
173
171
            raise AssertionError(
174
172
                'No decompressor to decompress %d bytes' % num_bytes)
175
173
        remaining_decomp = self._z_content_decompressor.unconsumed_tail
176
 
        if num_bytes is None:
177
 
            if remaining_decomp:
178
 
                # We don't know how much is left, but we'll decompress it all
179
 
                self._content += self._z_content_decompressor.decompress(
180
 
                    remaining_decomp)
181
 
                # Note: There's what I consider a bug in zlib.decompressobj
182
 
                #       If you pass back in the entire unconsumed_tail, only
183
 
                #       this time you don't pass a max-size, it doesn't
184
 
                #       change the unconsumed_tail back to None/''.
185
 
                #       However, we know we are done with the whole stream
186
 
                self._z_content_decompressor = None
187
 
            # XXX: Why is this the only place in this routine we set this?
188
 
            self._content_length = len(self._content)
189
 
        else:
190
 
            if not remaining_decomp:
191
 
                raise AssertionError('Nothing left to decompress')
192
 
            needed_bytes = num_bytes - len(self._content)
193
 
            # We always set max_size to 32kB over the minimum needed, so that
194
 
            # zlib will give us as much as we really want.
195
 
            # TODO: If this isn't good enough, we could make a loop here,
196
 
            #       that keeps expanding the request until we get enough
197
 
            self._content += self._z_content_decompressor.decompress(
198
 
                remaining_decomp, needed_bytes + _ZLIB_DECOMP_WINDOW)
199
 
            if len(self._content) < num_bytes:
200
 
                raise AssertionError('%d bytes wanted, only %d available'
201
 
                                     % (num_bytes, len(self._content)))
202
 
            if not self._z_content_decompressor.unconsumed_tail:
203
 
                # The stream is finished
204
 
                self._z_content_decompressor = None
 
174
        if not remaining_decomp:
 
175
            raise AssertionError('Nothing left to decompress')
 
176
        needed_bytes = num_bytes - len(self._content)
 
177
        # We always set max_size to 32kB over the minimum needed, so that
 
178
        # zlib will give us as much as we really want.
 
179
        # TODO: If this isn't good enough, we could make a loop here,
 
180
        #       that keeps expanding the request until we get enough
 
181
        self._content += self._z_content_decompressor.decompress(
 
182
            remaining_decomp, needed_bytes + _ZLIB_DECOMP_WINDOW)
 
183
        if len(self._content) < num_bytes:
 
184
            raise AssertionError('%d bytes wanted, only %d available'
 
185
                                 % (num_bytes, len(self._content)))
 
186
        if not self._z_content_decompressor.unconsumed_tail:
 
187
            # The stream is finished
 
188
            self._z_content_decompressor = None
205
189
 
206
190
    def _parse_bytes(self, bytes, pos):
207
191
        """Read the various lengths from the header.
1282
1266
        else:
1283
1267
            return self.get_record_stream(keys, 'unordered', True)
1284
1268
 
 
1269
    def clear_cache(self):
 
1270
        """See VersionedFiles.clear_cache()"""
 
1271
        self._group_cache.clear()
 
1272
        self._index._graph_index.clear_cache()
 
1273
        self._index._int_cache.clear()
 
1274
 
1285
1275
    def _check_add(self, key, lines, random_id, check_content):
1286
1276
        """check that version_id and lines are safe to add."""
1287
1277
        version_id = key[-1]
1757
1747
                key = record.key
1758
1748
            self._unadded_refs[key] = record.parents
1759
1749
            yield found_sha1
1760
 
            keys_to_add.append((key, '%d %d' % (start_point, end_point),
1761
 
                (record.parents,)))
 
1750
            as_st = static_tuple.StaticTuple.from_sequence
 
1751
            if record.parents is not None:
 
1752
                parents = as_st([as_st(p) for p in record.parents])
 
1753
            else:
 
1754
                parents = None
 
1755
            refs = static_tuple.StaticTuple(parents)
 
1756
            keys_to_add.append((key, '%d %d' % (start_point, end_point), refs))
1762
1757
        if len(keys_to_add):
1763
1758
            flush()
1764
1759
        self._compressor = None
1844
1839
        self.has_graph = parents
1845
1840
        self._is_locked = is_locked
1846
1841
        self._inconsistency_fatal = inconsistency_fatal
 
1842
        # GroupCompress records tend to have the same 'group' start + offset
 
1843
        # repeated over and over, this creates a surplus of ints
 
1844
        self._int_cache = {}
1847
1845
        if track_external_parent_refs:
1848
1846
            self._key_dependencies = knit._KeyRefs(
1849
1847
                track_new_keys=track_new_keys)
1885
1883
        if not random_id:
1886
1884
            present_nodes = self._get_entries(keys)
1887
1885
            for (index, key, value, node_refs) in present_nodes:
1888
 
                if node_refs != keys[key][1]:
1889
 
                    details = '%s %s %s' % (key, (value, node_refs), keys[key])
 
1886
                # Sometimes these are passed as a list rather than a tuple
 
1887
                node_refs = static_tuple.as_tuples(node_refs)
 
1888
                passed = static_tuple.as_tuples(keys[key])
 
1889
                if node_refs != passed[1]:
 
1890
                    details = '%s %s %s' % (key, (value, node_refs), passed)
1890
1891
                    if self._inconsistency_fatal:
1891
1892
                        raise errors.KnitCorrupt(self, "inconsistent details"
1892
1893
                                                 " in add_records: %s" %
2025
2026
        """Convert an index value to position details."""
2026
2027
        bits = node[2].split(' ')
2027
2028
        # It would be nice not to read the entire gzip.
 
2029
        # start and stop are put into _int_cache because they are very common.
 
2030
        # They define the 'group' that an entry is in, and many groups can have
 
2031
        # thousands of objects.
 
2032
        # Branching Launchpad, for example, saves ~600k integers, at 12 bytes
 
2033
        # each, or about 7MB. Note that it might be even more when you consider
 
2034
        # how PyInt is allocated in separate slabs. And you can't return a slab
 
2035
        # to the OS if even 1 int on it is in use. Note though that Python uses
 
2036
        # a LIFO when re-using PyInt slots, which probably causes more
 
2037
        # fragmentation.
2028
2038
        start = int(bits[0])
 
2039
        start = self._int_cache.setdefault(start, start)
2029
2040
        stop = int(bits[1])
 
2041
        stop = self._int_cache.setdefault(stop, stop)
2030
2042
        basis_end = int(bits[2])
2031
2043
        delta_end = int(bits[3])
2032
 
        return node[0], start, stop, basis_end, delta_end
 
2044
        # We can't use StaticTuple here, because node[0] is a BTreeGraphIndex
 
2045
        # instance...
 
2046
        return (node[0], start, stop, basis_end, delta_end)
2033
2047
 
2034
2048
    def scan_unvalidated_index(self, graph_index):
2035
2049
        """Inform this _GCGraphIndex that there is an unvalidated index.
2066
2080
        decode_base128_int,
2067
2081
        )
2068
2082
    GroupCompressor = PyrexGroupCompressor
2069
 
except ImportError:
 
2083
except ImportError, e:
 
2084
    osutils.failed_to_load_extension(e)
2070
2085
    GroupCompressor = PythonGroupCompressor
2071
2086