Field: fixed memory leak [#CLICKHOUSE-2756].

This commit is contained in:
Alexey Milovidov 2017-01-20 06:33:56 +03:00
parent 6226132be0
commit 7fa73c5462

View File

@ -79,6 +79,7 @@ public:
}
};
/// Позволяет получить идентификатор для типа или наоборот.
template <typename T> struct TypeToEnum;
template <Types::Which which> struct EnumToType;
@ -99,7 +100,7 @@ public:
Field(Field && rhs)
{
move(std::move(rhs));
create(std::move(rhs));
}
template <typename T>
@ -108,6 +109,12 @@ public:
create(rhs);
}
template <typename T>
Field(T && rhs)
{
create(std::move(rhs));
}
/// Создать строку inplace.
Field(const char * data, size_t size)
{
@ -119,6 +126,7 @@ public:
create(data, size);
}
/// NOTE In case when field already has string type, more direct assign is possible.
void assignString(const char * data, size_t size)
{
destroy();
@ -134,10 +142,15 @@ public:
Field & operator= (const Field & rhs)
{
if (this != &rhs)
{
if (which != rhs.which)
{
destroy();
create(rhs);
}
else
assign(rhs); /// This assigns string or vector without deallocation of existing buffer.
}
return *this;
}
@ -145,16 +158,42 @@ public:
{
if (this != &rhs)
{
move(std::move(rhs));
if (which != rhs.which)
{
destroy();
create(std::move(rhs));
}
else
assign(std::move(rhs));
}
return *this;
}
template <typename T>
Field & operator= (const T & rhs)
{
if (which != TypeToEnum<T>::value)
{
destroy();
create(rhs);
}
else
assign(rhs);
return *this;
}
template <typename T>
Field & operator= (T && rhs)
{
if (which != TypeToEnum<T>::value)
{
destroy();
create(std::move(rhs));
}
else
assign(std::move(rhs));
return *this;
}
@ -289,6 +328,7 @@ private:
Types::Which which;
/// Assuming there was no allocated state or it was deallocated (see destroy).
template <typename T>
void create(const T & x)
{
@ -297,25 +337,70 @@ private:
new (ptr) T(x);
}
void create(const Null & x)
template <typename T>
void create(T && x)
{
which = Types::Null;
which = TypeToEnum<T>::value;
T * __attribute__((__may_alias__)) ptr = reinterpret_cast<T*>(storage);
new (ptr) T(std::move(x));
}
/// Assuming same types.
template <typename T>
void assign(const T & x)
{
T * __attribute__((__may_alias__)) ptr = reinterpret_cast<T*>(storage);
*ptr = x;
}
template <typename T>
void assign(T && x)
{
T * __attribute__((__may_alias__)) ptr = reinterpret_cast<T*>(storage);
*ptr = std::move(x);
}
template <typename F, typename Field> /// Field template parameter may be const or non-const Field.
static void dispatch(F && f, Field & field)
{
switch (field.which)
{
case Types::Null: f(field.get<Null>()); return;
case Types::UInt64: f(field.get<UInt64>()); return;
case Types::Int64: f(field.get<Int64>()); return;
case Types::Float64: f(field.get<Float64>()); return;
case Types::String: f(field.get<String>()); return;
case Types::Array: f(field.get<Array>()); return;
case Types::Tuple: f(field.get<Tuple>()); return;
default:
throw Exception("Bad type of Field", ErrorCodes::BAD_TYPE_OF_FIELD);
}
}
void create(const Field & x)
{
switch (x.which)
dispatch([this] (auto & value) { create(value); }, x);
}
void create(Field && x)
{
case Types::Null: create(Null()); break;
case Types::UInt64: create(x.get<UInt64>()); break;
case Types::Int64: create(x.get<Int64>()); break;
case Types::Float64: create(x.get<Float64>()); break;
case Types::String: create(x.get<String>()); break;
case Types::Array: create(x.get<Array>()); break;
case Types::Tuple: create(x.get<Tuple>()); break;
dispatch([this] (auto & value) { create(std::move(value)); }, x);
}
void assign(const Field & x)
{
dispatch([this] (auto & value) { assign(value); }, x);
}
void assign(Field && x)
{
dispatch([this] (auto & value) { assign(std::move(value)); }, x);
}
void create(const char * data, size_t size)
{
which = Types::String;
@ -347,6 +432,8 @@ private:
default:
break;
}
which = Types::Null; /// for exception safety in subsequent calls to destroy and create, when create fails.
}
template <typename T>
@ -355,31 +442,6 @@ private:
T * __attribute__((__may_alias__)) ptr = reinterpret_cast<T*>(storage);
ptr->~T();
}
template <typename T>
void moveValue(Field && x)
{
T * __attribute__((__may_alias__)) ptr_this = reinterpret_cast<T*>(storage);
T * __attribute__((__may_alias__)) ptr_x = reinterpret_cast<T*>(x.storage);
new (ptr_this) T(std::move(*ptr_x));
}
void move(Field && x)
{
which = x.which;
switch (x.which)
{
case Types::Null: create(Null()); break;
case Types::UInt64: create(x.get<UInt64>()); break;
case Types::Int64: create(x.get<Int64>()); break;
case Types::Float64: create(x.get<Float64>()); break;
case Types::String: moveValue<String>(std::move(x)); break;
case Types::Array: moveValue<Array>(std::move(x)); break;
case Types::Tuple: moveValue<Tuple>(std::move(x)); break;
}
}
};
#undef DBMS_MIN_FIELD_SIZE