ClickHouse/src/Processors/Formats/Impl/AvroRowInputFormat.h

119 lines
3.8 KiB
C++
Raw Normal View History

#pragma once
#include "config_formats.h"
2020-01-18 19:29:53 +00:00
#include "config_core.h"
#if USE_AVRO
#include <unordered_map>
2020-02-01 04:13:12 +00:00
#include <map>
#include <vector>
#include <Core/Block.h>
#include <Formats/FormatSchemaInfo.h>
#include <Processors/Formats/IRowInputFormat.h>
#include <avro/DataFile.hh>
#include <avro/Decoder.hh>
#include <avro/Schema.hh>
#include <avro/ValidSchema.hh>
namespace DB
{
class AvroDeserializer
{
public:
2020-04-18 20:15:39 +00:00
AvroDeserializer(const Block & header, avro::ValidSchema schema);
2020-02-02 00:53:11 +00:00
void deserializeRow(MutableColumns & columns, avro::Decoder & decoder) const;
private:
using DeserializeFn = std::function<void(IColumn & column, avro::Decoder & decoder)>;
using SkipFn = std::function<void(avro::Decoder & decoder)>;
static DeserializeFn createDeserializeFn(avro::NodePtr root_node, DataTypePtr target_type);
2020-02-01 04:13:12 +00:00
SkipFn createSkipFn(avro::NodePtr root_node);
2020-04-18 20:15:39 +00:00
struct Action
{
enum Type { Deserialize, Skip };
Type type;
/// Deserialize
int target_column_idx;
DeserializeFn deserialize_fn;
/// Skip
SkipFn skip_fn;
Action(int target_column_idx_, DeserializeFn deserialize_fn_)
: type(Deserialize)
, target_column_idx(target_column_idx_)
, deserialize_fn(deserialize_fn_) {}
Action(SkipFn skip_fn_)
: type(Skip)
, skip_fn(skip_fn_) {}
void execute(MutableColumns & columns, avro::Decoder & decoder) const
{
2020-04-19 03:54:22 +00:00
switch (type)
2020-04-18 20:15:39 +00:00
{
case Deserialize:
deserialize_fn(*columns[target_column_idx], decoder);
break;
case Skip:
skip_fn(decoder);
break;
}
}
};
/// Populate actions by recursively traversing root schema
void createActions(const Block & header, const avro::NodePtr& node, std::string current_path = "");
/// Bitmap of columns found in Avro schema
std::vector<bool> column_found;
/// Deserialize/Skip actions for a row
std::vector<Action> actions;
2020-02-01 17:13:50 +00:00
/// Map from name of named Avro type (record, enum, fixed) to SkipFn.
2020-02-01 04:13:12 +00:00
/// This is to avoid infinite recursion when Avro schema contains self-references. e.g. LinkedList
2020-02-01 17:13:50 +00:00
std::map<avro::Name, SkipFn> symbolic_skip_fn_map;
};
class AvroRowInputFormat : public IRowInputFormat
{
public:
AvroRowInputFormat(const Block & header_, ReadBuffer & in_, Params params_);
virtual bool readRow(MutableColumns & columns, RowReadExtension & ext) override;
String getName() const override { return "AvroRowInputFormat"; }
private:
avro::DataFileReaderBase file_reader;
AvroDeserializer deserializer;
};
2020-01-18 19:29:53 +00:00
#if USE_POCO_JSON
2020-02-02 00:53:11 +00:00
/// Confluent framing + Avro binary datum encoding. Mainly used for Kafka.
/// Uses 3 caches:
/// 1. global: schema registry cache (base_url -> SchemaRegistry)
/// 2. SchemaRegistry: schema cache (schema_id -> schema)
/// 3. AvroConfluentRowInputFormat: deserializer cache (schema_id -> AvroDeserializer)
/// This is needed because KafkaStorage creates a new instance of InputFormat per a batch of messages
class AvroConfluentRowInputFormat : public IRowInputFormat
{
public:
AvroConfluentRowInputFormat(const Block & header_, ReadBuffer & in_, Params params_, const FormatSettings & format_settings_);
virtual bool readRow(MutableColumns & columns, RowReadExtension & ext) override;
String getName() const override { return "AvroConfluentRowInputFormat"; }
2020-02-02 00:53:11 +00:00
class SchemaRegistry;
private:
2020-02-02 00:53:11 +00:00
std::shared_ptr<SchemaRegistry> schema_registry;
using SchemaId = uint32_t;
std::unordered_map<SchemaId, AvroDeserializer> deserializer_cache;
2020-02-02 00:53:11 +00:00
const AvroDeserializer & getOrCreateDeserializer(SchemaId schema_id);
avro::InputStreamPtr input_stream;
avro::DecoderPtr decoder;
};
2020-01-10 22:46:48 +00:00
#endif
}
#endif