def _decode_message(cls, data, offset): """ Decode a single Message The only caller of this method is decode_message_set_iter. They are decoupled to support nested messages (compressed MessageSets). The offset is actually read from decode_message_set_iter (it is part of the MessageSet payload). """ ((crc, magic, att), cur) = relative_unpack('>iBB', data, 0) if crc != zlib.crc32(data[4:]): raise ChecksumError("Message checksum failed") (key, cur) = read_int_string(data, cur) (value, cur) = read_int_string(data, cur) codec = att & ATTRIBUTE_CODEC_MASK if codec == CODEC_NONE.mask: yield (offset, Message(magic, att, key, value)) else: decoders = filter(lambda c: c.mask == codec, ALL_CODECS) if decoders: message_set = decoders[0].decode(value) for (offset, msg) in KafkaProtocol._decode_message_set_iter(message_set): yield (offset, msg) else: raise UnsupportedCodecError('FILL ME IN')
def _decode_message(cls, data, offset): """ Decode a single Message The only caller of this method is decode_message_set_iter. They are decoupled to support nested messages (compressed MessageSets). The offset is actually read from decode_message_set_iter (it is part of the MessageSet payload). """ ((crc, magic, att), cur) = relative_unpack('>iBB', data, 0) if crc != zlib.crc32(data[4:]): raise ChecksumError("Message checksum failed") (key, cur) = read_int_string(data, cur) (value, cur) = read_int_string(data, cur) codec = att & KafkaProtocol.ATTRIBUTE_CODEC_MASK if codec == KafkaProtocol.CODEC_NONE: yield (offset, Message(magic, att, key, value)) elif codec == KafkaProtocol.CODEC_GZIP: gz = gzip_decode(value) for (offset, msg) in KafkaProtocol._decode_message_set_iter(gz): yield (offset, msg) elif codec == KafkaProtocol.CODEC_SNAPPY: snp = snappy_decode(value) for (offset, msg) in KafkaProtocol._decode_message_set_iter(snp): yield (offset, msg)
def _decode_message(cls, data, offset): """ Decode a single Message The only caller of this method is decode_message_set_iter. They are decoupled to support nested messages (compressed MessageSets). The offset is actually read from decode_message_set_iter (it is part of the MessageSet payload). """ ((crc, magic, att), cur) = relative_unpack('>IBB', data, 0) if crc != crc32(data[4:]): raise ChecksumError("Message checksum failed") (key, cur) = read_int_string(data, cur) (value, cur) = read_int_string(data, cur) codec = att & ATTRIBUTE_CODEC_MASK if codec == CODEC_NONE: yield (offset, Message(magic, att, key, value)) elif codec == CODEC_GZIP: gz = gzip_decode(value) for (offset, msg) in KafkaProtocol._decode_message_set_iter(gz): yield (offset, msg) elif codec == CODEC_SNAPPY: snp = snappy_decode(value) for (offset, msg) in KafkaProtocol._decode_message_set_iter(snp): yield (offset, msg)
def _decode_message_set_iter(cls, data): """ Iteratively decode a MessageSet Reads repeated elements of (offset, message), calling decode_message to decode a single message. Since compressed messages contain futher MessageSets, these two methods have been decoupled so that they may recurse easily. """ cur = 0 read_message = False while cur < len(data): try: ((offset, ), cur) = relative_unpack('>q', data, cur) (msg, cur) = read_int_string(data, cur) for (offset, message) in KafkaProtocol._decode_message(msg, offset): read_message = True yield OffsetAndMessage(offset, message) except BufferUnderflowError: # NOTE: Not sure this is correct error handling: # Is it possible to get a BUE if the message set is somewhere # in the middle of the fetch response? If so, we probably have # an issue that's not fetch size too small. # Aren't we ignoring errors if we fail to unpack data by # raising StopIteration()? # If _decode_message() raises a ChecksumError, couldn't that # also be due to the fetch size being too small? if read_message is False: # If we get a partial read of a message, but haven't # yielded anything there's a problem raise ConsumerFetchSizeTooSmall() else: raise StopIteration()
def _decode_message_set_iter(cls, data): """ Iteratively decode a MessageSet Reads repeated elements of (offset, message), calling decode_message to decode a single message. Since compressed messages contain futher MessageSets, these two methods have been decoupled so that they may recurse easily. """ cur = 0 read_message = False while cur < len(data): try: ((offset, ), cur) = relative_unpack('>q', data, cur) (msg, cur) = read_int_string(data, cur) for (offset, message) in KafkaProtocol._decode_message(msg, offset): read_message = True yield OffsetAndMessage(offset, message) except BufferUnderflowError: if read_message is False: # If we get a partial read of a message, but haven't # yielded anyhting there's a problem raise ConsumerFetchSizeTooSmall() else: raise StopIteration()
def _decode_message_set_iter(cls, data): """ Iteratively decode a MessageSet Reads repeated elements of (offset, message), calling decode_message to decode a single message. Since compressed messages contain futher MessageSets, these two methods have been decoupled so that they may recurse easily. """ cur = 0 read_message = False while cur < len(data): try: ((offset, ), cur) = relative_unpack('>q', data, cur) (msg, cur) = read_int_string(data, cur) for (offset, message) in KafkaProtocol._decode_message(msg, offset): read_message = True yield OffsetAndMessage(offset, message) except BufferUnderflowError: if read_message is False: # If we get a partial read of a message, but haven't yielded anyhting # there's a problem raise ConsumerFetchSizeTooSmall() else: raise StopIteration()
def decode_fetch_response(cls, data): """ Decode bytes to a FetchResponse Params ====== data: bytes to decode """ ((correlation_id, num_topics), cur) = relative_unpack('>ii', data, 0) for i in range(num_topics): (topic, cur) = read_short_string(data, cur) ((num_partitions,), cur) = relative_unpack('>i', data, cur) for i in range(num_partitions): ((partition, error, highwater_mark_offset), cur) = relative_unpack('>ihq', data, cur) (message_set, cur) = read_int_string(data, cur) yield FetchResponse(topic, partition, error, highwater_mark_offset, KafkaProtocol._decode_message_set_iter(message_set))
def _decode_message_set_iter(cls, data): """ Iteratively decode a MessageSet Reads repeated elements of (offset, message), calling decode_message to decode a single message. Since compressed messages contain futher MessageSets, these two methods have been decoupled so that they may recurse easily. """ cur = 0 while cur < len(data): try: ((offset, ), cur) = relative_unpack('>q', data, cur) (msg, cur) = read_int_string(data, cur) for (offset, message) in KafkaProtocol._decode_message(msg, offset): yield OffsetAndMessage(offset, message) except BufferUnderflowError: # If we get a partial read of a message, stop raise StopIteration()
def decode_fetch_response(cls, data): """ Decode bytes to a FetchResponse Arguments: data: bytes to decode """ ((correlation_id, num_topics), cur) = relative_unpack('>ii', data, 0) for _ in range(num_topics): (topic, cur) = read_short_string(data, cur) ((num_partitions, ), cur) = relative_unpack('>i', data, cur) for j in range(num_partitions): ((partition, error, highwater_mark_offset), cur) = \ relative_unpack('>ihq', data, cur) (message_set, cur) = read_int_string(data, cur) yield FetchResponse( topic, partition, error, highwater_mark_offset, KafkaProtocol._decode_message_set_iter(message_set))