~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/groupcompress.py

Rework test_script a little bit.


Don't allow someone to request a stdin request to echo.
Echo never reads from stdin, it just echos its arguments.
You use 'cat' if you want to read from stdin.

A few other fixes because the tests were using filenames
that are actually illegal on Windows, rather than just
nonexistant.


Change the exception handling for commands so that
unknown errors don't get silently squashed and then
turn into hard-to-debug errors later.

test_script now passes on Windows.

Show diffs side-by-side

added added

removed removed

Lines of Context:
119
119
        :param num_bytes: Ensure that we have extracted at least num_bytes of
120
120
            content. If None, consume everything
121
121
        """
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.
 
122
        if self._content_length is None:
 
123
            raise AssertionError('self._content_length should never be None')
129
124
        if num_bytes is None:
130
125
            num_bytes = self._content_length
131
126
        elif (self._content_length is not None
148
143
                self._content = pylzma.decompress(self._z_content)
149
144
            elif self._compressor_name == 'zlib':
150
145
                # Start a zlib decompressor
151
 
                if num_bytes is None:
 
146
                if num_bytes * 4 > self._content_length * 3:
 
147
                    # If we are requesting more that 3/4ths of the content,
 
148
                    # just extract the whole thing in a single pass
 
149
                    num_bytes = self._content_length
152
150
                    self._content = zlib.decompress(self._z_content)
153
151
                else:
154
152
                    self._z_content_decompressor = zlib.decompressobj()
156
154
                    # that the rest of the code is simplified
157
155
                    self._content = self._z_content_decompressor.decompress(
158
156
                        self._z_content, num_bytes + _ZLIB_DECOMP_WINDOW)
 
157
                    if not self._z_content_decompressor.unconsumed_tail:
 
158
                        self._z_content_decompressor = None
159
159
            else:
160
160
                raise AssertionError('Unknown compressor: %r'
161
161
                                     % self._compressor_name)
163
163
        # 'unconsumed_tail'
164
164
 
165
165
        # 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
 
166
        if len(self._content) >= num_bytes:
170
167
            return
171
168
        # If we got this far, and don't have a decompressor, something is wrong
172
169
        if self._z_content_decompressor is None:
173
170
            raise AssertionError(
174
171
                'No decompressor to decompress %d bytes' % num_bytes)
175
172
        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
 
173
        if not remaining_decomp:
 
174
            raise AssertionError('Nothing left to decompress')
 
175
        needed_bytes = num_bytes - len(self._content)
 
176
        # We always set max_size to 32kB over the minimum needed, so that
 
177
        # zlib will give us as much as we really want.
 
178
        # TODO: If this isn't good enough, we could make a loop here,
 
179
        #       that keeps expanding the request until we get enough
 
180
        self._content += self._z_content_decompressor.decompress(
 
181
            remaining_decomp, needed_bytes + _ZLIB_DECOMP_WINDOW)
 
182
        if len(self._content) < num_bytes:
 
183
            raise AssertionError('%d bytes wanted, only %d available'
 
184
                                 % (num_bytes, len(self._content)))
 
185
        if not self._z_content_decompressor.unconsumed_tail:
 
186
            # The stream is finished
 
187
            self._z_content_decompressor = None
205
188
 
206
189
    def _parse_bytes(self, bytes, pos):
207
190
        """Read the various lengths from the header.
1282
1265
        else:
1283
1266
            return self.get_record_stream(keys, 'unordered', True)
1284
1267
 
 
1268
    def clear_cache(self):
 
1269
        """See VersionedFiles.clear_cache()"""
 
1270
        self._group_cache.clear()
 
1271
        self._index._graph_index.clear_cache()
 
1272
        self._index._int_cache.clear()
 
1273
 
1285
1274
    def _check_add(self, key, lines, random_id, check_content):
1286
1275
        """check that version_id and lines are safe to add."""
1287
1276
        version_id = key[-1]
1844
1833
        self.has_graph = parents
1845
1834
        self._is_locked = is_locked
1846
1835
        self._inconsistency_fatal = inconsistency_fatal
 
1836
        # GroupCompress records tend to have the same 'group' start + offset
 
1837
        # repeated over and over, this creates a surplus of ints
 
1838
        self._int_cache = {}
1847
1839
        if track_external_parent_refs:
1848
1840
            self._key_dependencies = knit._KeyRefs(
1849
1841
                track_new_keys=track_new_keys)
2025
2017
        """Convert an index value to position details."""
2026
2018
        bits = node[2].split(' ')
2027
2019
        # It would be nice not to read the entire gzip.
 
2020
        # start and stop are put into _int_cache because they are very common.
 
2021
        # They define the 'group' that an entry is in, and many groups can have
 
2022
        # thousands of objects.
 
2023
        # Branching Launchpad, for example, saves ~600k integers, at 12 bytes
 
2024
        # each, or about 7MB. Note that it might be even more when you consider
 
2025
        # how PyInt is allocated in separate slabs. And you can't return a slab
 
2026
        # to the OS if even 1 int on it is in use. Note though that Python uses
 
2027
        # a LIFO when re-using PyInt slots, which probably causes more
 
2028
        # fragmentation.
2028
2029
        start = int(bits[0])
 
2030
        start = self._int_cache.setdefault(start, start)
2029
2031
        stop = int(bits[1])
 
2032
        stop = self._int_cache.setdefault(stop, stop)
2030
2033
        basis_end = int(bits[2])
2031
2034
        delta_end = int(bits[3])
2032
 
        return node[0], start, stop, basis_end, delta_end
 
2035
        # We can't use StaticTuple here, because node[0] is a BTreeGraphIndex
 
2036
        # instance...
 
2037
        return (node[0], start, stop, basis_end, delta_end)
2033
2038
 
2034
2039
    def scan_unvalidated_index(self, graph_index):
2035
2040
        """Inform this _GCGraphIndex that there is an unvalidated index.
2066
2071
        decode_base128_int,
2067
2072
        )
2068
2073
    GroupCompressor = PyrexGroupCompressor
2069
 
except ImportError:
 
2074
except ImportError, e:
 
2075
    osutils.failed_to_load_extension(e)
2070
2076
    GroupCompressor = PythonGroupCompressor
2071
2077