Merge pull request #49 from yandex/METR-18844

Metr 18844
This commit is contained in:
alexey-milovidov 2016-07-10 12:43:19 +03:00 committed by GitHub
commit e4c62935c3
5 changed files with 605 additions and 32 deletions

View File

@ -8,6 +8,7 @@
#include <boost/range/iterator_range_core.hpp> #include <boost/range/iterator_range_core.hpp>
#include <DB/Parsers/ExpressionElementParsers.h> #include <DB/Parsers/ExpressionElementParsers.h>
#include <DB/Parsers/ASTLiteral.h> #include <DB/Parsers/ASTLiteral.h>
#include <DB/Common/PODArray.h>
#include <bitset> #include <bitset>
#include <stack> #include <stack>
@ -44,7 +45,8 @@ struct AggregateFunctionSequenceMatchData final
using Comparator = ComparePairFirst<std::less>; using Comparator = ComparePairFirst<std::less>;
bool sorted = true; bool sorted = true;
std::vector<TimestampEvents> eventsList; static constexpr size_t bytes_in_arena = 64;
PODArray<TimestampEvents, bytes_in_arena, AllocatorWithStackMemory<Allocator<false>, bytes_in_arena>> eventsList;
void add(const Timestamp timestamp, const Events & events) void add(const Timestamp timestamp, const Events & events)
{ {
@ -60,7 +62,7 @@ struct AggregateFunctionSequenceMatchData final
{ {
const auto size = eventsList.size(); const auto size = eventsList.size();
eventsList.insert(std::end(eventsList), std::begin(other.eventsList), std::end(other.eventsList)); eventsList.insert(std::begin(other.eventsList), std::end(other.eventsList));
/// either sort whole container or do so partially merging ranges afterwards /// either sort whole container or do so partially merging ranges afterwards
if (!sorted && !other.sorted) if (!sorted && !other.sorted)
@ -111,7 +113,7 @@ struct AggregateFunctionSequenceMatchData final
std::size_t size; std::size_t size;
readBinary(size, buf); readBinary(size, buf);
decltype(eventsList) eventsList; eventsList.clear();
eventsList.reserve(size); eventsList.reserve(size);
for (std::size_t i = 0; i < size; ++i) for (std::size_t i = 0; i < size; ++i)
@ -124,8 +126,6 @@ struct AggregateFunctionSequenceMatchData final
eventsList.emplace_back(timestamp, Events{events}); eventsList.emplace_back(timestamp, Events{events});
} }
this->eventsList = std::move(eventsList);
} }
}; };
@ -262,14 +262,14 @@ private:
PatternAction(const PatternActionType type, const std::uint32_t extra = 0) : type{type}, extra{extra} {} PatternAction(const PatternActionType type, const std::uint32_t extra = 0) : type{type}, extra{extra} {}
}; };
using PatternActions = std::vector<PatternAction>; static constexpr size_t bytes_on_stack = 64;
using PatternActions = PODArray<PatternAction, bytes_on_stack, AllocatorWithStackMemory<Allocator<false>, bytes_on_stack>>;
void parsePattern() void parsePattern()
{ {
PatternActions actions{ actions.clear();
{ PatternActionType::KleeneStar } actions.emplace_back(PatternActionType::KleeneStar);
};
ParserString special_open_p("(?"); ParserString special_open_p("(?");
ParserString special_close_p(")"); ParserString special_close_p(")");
@ -354,8 +354,6 @@ private:
else else
throw_exception("Could not parse pattern, unexpected starting symbol"); throw_exception("Could not parse pattern, unexpected starting symbol");
} }
this->actions = std::move(actions);
} }
protected: protected:

View File

@ -164,6 +164,12 @@ public:
return buf; return buf;
} }
protected:
static constexpr size_t getStackThreshold()
{
return 0;
}
}; };
@ -209,6 +215,12 @@ public:
memcpy(new_buf, buf, old_size); memcpy(new_buf, buf, old_size);
return new_buf; return new_buf;
} }
protected:
static constexpr size_t getStackThreshold()
{
return N;
}
}; };

View File

@ -109,6 +109,17 @@ private:
c_end_of_storage = c_start + bytes - pad_right; c_end_of_storage = c_start + bytes - pad_right;
} }
bool isInitialized() const
{
return (c_start != nullptr) && (c_end != nullptr) && (c_end_of_storage != nullptr);
}
bool isAllocatedFromStack() const
{
constexpr size_t stack_threshold = TAllocator::getStackThreshold();
return (stack_threshold > 0) && (allocated_size() <= stack_threshold);
}
public: public:
using value_type = T; using value_type = T;
@ -130,55 +141,46 @@ public:
PODArray() {} PODArray() {}
PODArray(size_t n) PODArray(size_t n)
{ {
alloc_for_num_elements(n); alloc_for_num_elements(n);
c_end += byte_size(n); c_end += byte_size(n);
} }
PODArray(size_t n, const T & x) PODArray(size_t n, const T & x)
{ {
alloc_for_num_elements(n); alloc_for_num_elements(n);
assign(n, x); assign(n, x);
} }
PODArray(const_iterator from_begin, const_iterator from_end) PODArray(const_iterator from_begin, const_iterator from_end)
{ {
alloc_for_num_elements(from_end - from_begin); alloc_for_num_elements(from_end - from_begin);
insert(from_begin, from_end); insert(from_begin, from_end);
} }
~PODArray() ~PODArray()
{ {
dealloc(); dealloc();
} }
PODArray(PODArray && other) PODArray(PODArray && other)
{ {
c_start = other.c_start; this->swap(other);
c_end = other.c_end;
c_end_of_storage = other.c_end_of_storage;
other.c_start = nullptr;
other.c_end = nullptr;
other.c_end_of_storage = nullptr;
} }
PODArray & operator=(PODArray && other) PODArray & operator=(PODArray && other)
{ {
std::swap(c_start, other.c_start); this->swap(other);
std::swap(c_end, other.c_end);
std::swap(c_end_of_storage, other.c_end_of_storage);
return *this; return *this;
} }
T * data() { return t_start(); } T * data() { return t_start(); }
const T * data() const { return t_start(); } const T * data() const { return t_start(); }
size_t size() const { return t_end() - t_start(); } size_t size() const { return t_end() - t_start(); }
bool empty() const { return t_end() == t_start(); } bool empty() const { return t_end() == t_start(); }
size_t capacity() const { return t_end_of_storage() - t_start(); } size_t capacity() const { return t_end_of_storage() - t_start(); }
T & operator[] (size_t n) { return t_start()[n]; } T & operator[] (size_t n) { return t_start()[n]; }
const T & operator[] (size_t n) const { return t_start()[n]; } const T & operator[] (size_t n) const { return t_start()[n]; }
@ -310,9 +312,107 @@ public:
void swap(PODArray & rhs) void swap(PODArray & rhs)
{ {
std::swap(c_start, rhs.c_start); /// Swap two PODArray objects, arr1 and arr2, that satisfy the following conditions:
std::swap(c_end, rhs.c_end); /// - The elements of arr1 are stored on stack.
std::swap(c_end_of_storage, rhs.c_end_of_storage); /// - The elements of arr2 are stored on heap.
auto swap_stack_heap = [](PODArray & arr1, PODArray & arr2)
{
size_t stack_size = arr1.size();
size_t stack_allocated = arr1.allocated_size();
size_t heap_size = arr2.size();
size_t heap_allocated = arr2.allocated_size();
/// Keep track of the stack content we have to copy.
char * stack_c_start = arr1.c_start;
/// arr1 takes ownership of the heap memory of arr2.
arr1.c_start = arr2.c_start;
arr1.c_end_of_storage = arr1.c_start + heap_allocated - arr1.pad_right;
arr1.c_end = arr1.c_start + byte_size(heap_size);
/// Allocate stack space for arr2.
arr2.alloc(stack_allocated);
/// Copy the stack content.
memcpy(arr2.c_start, stack_c_start, byte_size(stack_size));
arr2.c_end = arr2.c_start + byte_size(stack_size);
};
auto do_move = [](PODArray & src, PODArray & dest)
{
if (src.isAllocatedFromStack())
{
dest.dealloc();
dest.alloc(src.allocated_size());
memcpy(dest.c_start, src.c_start, byte_size(src.size()));
dest.c_end = dest.c_start + (src.c_end - src.c_start);
src.c_start = nullptr;
src.c_end = nullptr;
src.c_end_of_storage = nullptr;
}
else
{
std::swap(dest.c_start, src.c_start);
std::swap(dest.c_end, src.c_end);
std::swap(dest.c_end_of_storage, src.c_end_of_storage);
}
};
if (!isInitialized() && !rhs.isInitialized())
return;
else if (!isInitialized() && rhs.isInitialized())
{
do_move(rhs, *this);
return;
}
else if (isInitialized() && !rhs.isInitialized())
{
do_move(*this, rhs);
return;
}
if (isAllocatedFromStack() && rhs.isAllocatedFromStack())
{
size_t min_size = std::min(size(), rhs.size());
size_t max_size = std::max(size(), rhs.size());
for (size_t i = 0; i < min_size; ++i)
std::swap(this->operator[](i), rhs[i]);
if (size() == max_size)
{
for (size_t i = min_size; i < max_size; ++i)
rhs[i] = this->operator[](i);
}
else
{
for (size_t i = min_size; i < max_size; ++i)
this->operator[](i) = rhs[i];
}
size_t lhs_size = size();
size_t lhs_allocated = allocated_size();
size_t rhs_size = rhs.size();
size_t rhs_allocated = rhs.allocated_size();
c_end_of_storage = c_start + rhs_allocated - pad_right;
rhs.c_end_of_storage = rhs.c_start + lhs_allocated - pad_right;
c_end = c_start + byte_size(rhs_size);
rhs.c_end = rhs.c_start + byte_size(lhs_size);
}
else if (isAllocatedFromStack() && !rhs.isAllocatedFromStack())
swap_stack_heap(*this, rhs);
else if (!isAllocatedFromStack() && rhs.isAllocatedFromStack())
swap_stack_heap(rhs, *this);
else
{
std::swap(c_start, rhs.c_start);
std::swap(c_end, rhs.c_end);
std::swap(c_end_of_storage, rhs.c_end_of_storage);
}
} }
void assign(size_t n, const T & x) void assign(size_t n, const T & x)
@ -365,6 +465,11 @@ public:
} }
}; };
template <typename T, size_t INITIAL_SIZE, typename TAllocator, size_t pad_right_>
void swap(PODArray<T, INITIAL_SIZE, TAllocator, pad_right_> & lhs, PODArray<T, INITIAL_SIZE, TAllocator, pad_right_> & rhs)
{
lhs.swap(rhs);
}
/** Для столбцов. Padding-а хватает, чтобы читать и писать xmm-регистр по адресу последнего элемента. */ /** Для столбцов. Padding-а хватает, чтобы читать и писать xmm-регистр по адресу последнего элемента. */
template <typename T, size_t INITIAL_SIZE = 4096, typename TAllocator = Allocator<false>> template <typename T, size_t INITIAL_SIZE = 4096, typename TAllocator = Allocator<false>>

View File

@ -42,3 +42,6 @@ target_link_libraries (shell_command_test dbms)
add_executable (arena_with_free_lists arena_with_free_lists.cpp) add_executable (arena_with_free_lists arena_with_free_lists.cpp)
target_link_libraries (arena_with_free_lists dbms) target_link_libraries (arena_with_free_lists dbms)
add_executable (pod_array pod_array.cpp)
target_link_libraries (pod_array dbms)

View File

@ -0,0 +1,455 @@
#include <DB/Common/PODArray.h>
#include <DB/Core/Types.h>
#include <iostream>
#define ASSERT_CHECK(cond, res) \
do \
{ \
if (!(cond)) \
{ \
std::cerr << __FILE__ << ":" << __LINE__ << ":" \
<< "Assertion " << #cond << " failed.\n"; \
if ((res)) { (res) = false; } \
} \
} \
while (0)
void test1()
{
using namespace DB;
static constexpr size_t initial_size = 8;
static constexpr size_t stack_threshold = 32;
using Array = PODArray<UInt64, initial_size, AllocatorWithStackMemory<Allocator<false>, stack_threshold>>;
bool res = true;
{
Array arr;
Array arr2;
arr2 = std::move(arr);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2 = std::move(arr);
ASSERT_CHECK((arr2.size() == 3), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
arr = std::move(arr2);
ASSERT_CHECK((arr.size() == 3), res);
ASSERT_CHECK((arr[0] == 1), res);
ASSERT_CHECK((arr[1] == 2), res);
ASSERT_CHECK((arr[2] == 3), res);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
Array arr2;
arr2 = std::move(arr);
ASSERT_CHECK((arr2.size() == 5), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
ASSERT_CHECK((arr2[3] == 4), res);
ASSERT_CHECK((arr2[4] == 5), res);
arr = std::move(arr2);
ASSERT_CHECK((arr.size() == 5), res);
ASSERT_CHECK((arr[0] == 1), res);
ASSERT_CHECK((arr[1] == 2), res);
ASSERT_CHECK((arr[2] == 3), res);
ASSERT_CHECK((arr[3] == 4), res);
ASSERT_CHECK((arr[4] == 5), res);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2.push_back(4);
arr2.push_back(5);
arr2.push_back(6);
arr2.push_back(7);
arr2 = std::move(arr);
ASSERT_CHECK((arr2.size() == 3), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2.push_back(4);
arr2.push_back(5);
arr2.push_back(6);
arr2.push_back(7);
arr2.push_back(8);
arr = std::move(arr2);
ASSERT_CHECK((arr.size() == 5), res);
ASSERT_CHECK((arr[0] == 4), res);
ASSERT_CHECK((arr[1] == 5), res);
ASSERT_CHECK((arr[2] == 6), res);
ASSERT_CHECK((arr[3] == 7), res);
ASSERT_CHECK((arr[4] == 8), res);
}
if (!res)
std::cerr << "Some errors were found in test 1\n";
}
void test2()
{
using namespace DB;
static constexpr size_t initial_size = 8;
static constexpr size_t stack_threshold = 32;
using Array = PODArray<UInt64, initial_size, AllocatorWithStackMemory<Allocator<false>, stack_threshold>>;
bool res = true;
{
Array arr;
Array arr2;
arr.swap(arr2);
arr2.swap(arr);
}
{
Array arr;
Array arr2;
arr2.push_back(1);
arr2.push_back(2);
arr2.push_back(3);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 3), res);
ASSERT_CHECK((arr[0] == 1), res);
ASSERT_CHECK((arr[1] == 2), res);
ASSERT_CHECK((arr[2] == 3), res);
ASSERT_CHECK((arr2.size() == 0), res);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 0), res);
ASSERT_CHECK((arr2.size() == 3), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
}
{
Array arr;
Array arr2;
arr2.push_back(1);
arr2.push_back(2);
arr2.push_back(3);
arr2.push_back(4);
arr2.push_back(5);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 5), res);
ASSERT_CHECK((arr[0] == 1), res);
ASSERT_CHECK((arr[1] == 2), res);
ASSERT_CHECK((arr[2] == 3), res);
ASSERT_CHECK((arr[3] == 4), res);
ASSERT_CHECK((arr[4] == 5), res);
ASSERT_CHECK((arr2.size() == 0), res);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 0), res);
ASSERT_CHECK((arr2.size() == 5), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
ASSERT_CHECK((arr2[3] == 4), res);
ASSERT_CHECK((arr2[4] == 5), res);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2.push_back(4);
arr2.push_back(5);
arr2.push_back(6);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 3), res);
ASSERT_CHECK((arr[0] == 4), res);
ASSERT_CHECK((arr[1] == 5), res);
ASSERT_CHECK((arr[2] == 6), res);
ASSERT_CHECK((arr2.size() == 3), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 3), res);
ASSERT_CHECK((arr[0] == 1), res);
ASSERT_CHECK((arr[1] == 2), res);
ASSERT_CHECK((arr[2] == 3), res);
ASSERT_CHECK((arr2.size() == 3), res);
ASSERT_CHECK((arr2[0] == 4), res);
ASSERT_CHECK((arr2[1] == 5), res);
ASSERT_CHECK((arr2[2] == 6), res);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
Array arr2;
arr2.push_back(3);
arr2.push_back(4);
arr2.push_back(5);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 3), res);
ASSERT_CHECK((arr[0] == 3), res);
ASSERT_CHECK((arr[1] == 4), res);
ASSERT_CHECK((arr[2] == 5), res);
ASSERT_CHECK((arr2.size() == 2), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 2), res);
ASSERT_CHECK((arr[0] == 1), res);
ASSERT_CHECK((arr[1] == 2), res);
ASSERT_CHECK((arr2.size() == 3), res);
ASSERT_CHECK((arr2[0] == 3), res);
ASSERT_CHECK((arr2[1] == 4), res);
ASSERT_CHECK((arr2[2] == 5), res);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2;
arr2.push_back(4);
arr2.push_back(5);
arr2.push_back(6);
arr2.push_back(7);
arr2.push_back(8);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 5), res);
ASSERT_CHECK((arr[0] == 4), res);
ASSERT_CHECK((arr[1] == 5), res);
ASSERT_CHECK((arr[2] == 6), res);
ASSERT_CHECK((arr[3] == 7), res);
ASSERT_CHECK((arr[4] == 8), res);
ASSERT_CHECK((arr2.size() == 3), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 3), res);
ASSERT_CHECK((arr[0] == 1), res);
ASSERT_CHECK((arr[1] == 2), res);
ASSERT_CHECK((arr[2] == 3), res);
ASSERT_CHECK((arr2.size() == 5), res);
ASSERT_CHECK((arr2[0] == 4), res);
ASSERT_CHECK((arr2[1] == 5), res);
ASSERT_CHECK((arr2[2] == 6), res);
ASSERT_CHECK((arr2[3] == 7), res);
ASSERT_CHECK((arr2[4] == 8), res);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
Array arr2;
arr2.push_back(6);
arr2.push_back(7);
arr2.push_back(8);
arr2.push_back(9);
arr2.push_back(10);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 5), res);
ASSERT_CHECK((arr[0] == 6), res);
ASSERT_CHECK((arr[1] == 7), res);
ASSERT_CHECK((arr[2] == 8), res);
ASSERT_CHECK((arr[3] == 9), res);
ASSERT_CHECK((arr[4] == 10), res);
ASSERT_CHECK((arr2.size() == 5), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
ASSERT_CHECK((arr2[3] == 4), res);
ASSERT_CHECK((arr2[4] == 5), res);
arr.swap(arr2);
ASSERT_CHECK((arr.size() == 5), res);
ASSERT_CHECK((arr[0] == 1), res);
ASSERT_CHECK((arr[1] == 2), res);
ASSERT_CHECK((arr[2] == 3), res);
ASSERT_CHECK((arr[3] == 4), res);
ASSERT_CHECK((arr[4] == 5), res);
ASSERT_CHECK((arr2.size() == 5), res);
ASSERT_CHECK((arr2[0] == 6), res);
ASSERT_CHECK((arr2[1] == 7), res);
ASSERT_CHECK((arr2[2] == 8), res);
ASSERT_CHECK((arr2[3] == 9), res);
ASSERT_CHECK((arr2[4] == 10), res);
}
if (!res)
std::cerr << "Some errors were found in test 2\n";
}
void test3()
{
using namespace DB;
static constexpr size_t initial_size = 8;
static constexpr size_t stack_threshold = 32;
using Array = PODArray<UInt64, initial_size, AllocatorWithStackMemory<Allocator<false>, stack_threshold>>;
bool res = true;
{
Array arr;
Array arr2{std::move(arr)};
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
Array arr2{std::move(arr)};
ASSERT_CHECK((arr.size() == 0), res);
ASSERT_CHECK((arr2.size() == 3), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
}
{
Array arr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
Array arr2{std::move(arr)};
ASSERT_CHECK((arr.size() == 0), res);
ASSERT_CHECK((arr2.size() == 5), res);
ASSERT_CHECK((arr2[0] == 1), res);
ASSERT_CHECK((arr2[1] == 2), res);
ASSERT_CHECK((arr2[2] == 3), res);
ASSERT_CHECK((arr2[3] == 4), res);
ASSERT_CHECK((arr2[4] == 5), res);
}
if (!res)
std::cerr << "Some errors were found in test 3\n";
}
int main()
{
std::cout << "test 1\n";
test1();
std::cout << "test 2\n";
test2();
std::cout << "test 3\n";
test3();
return 0;
}