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 <DB/Parsers/ExpressionElementParsers.h>
#include <DB/Parsers/ASTLiteral.h>
#include <DB/Common/PODArray.h>
#include <bitset>
#include <stack>
@ -44,7 +45,8 @@ struct AggregateFunctionSequenceMatchData final
using Comparator = ComparePairFirst<std::less>;
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)
{
@ -60,7 +62,7 @@ struct AggregateFunctionSequenceMatchData final
{
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
if (!sorted && !other.sorted)
@ -111,7 +113,7 @@ struct AggregateFunctionSequenceMatchData final
std::size_t size;
readBinary(size, buf);
decltype(eventsList) eventsList;
eventsList.clear();
eventsList.reserve(size);
for (std::size_t i = 0; i < size; ++i)
@ -124,8 +126,6 @@ struct AggregateFunctionSequenceMatchData final
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} {}
};
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()
{
PatternActions actions{
{ PatternActionType::KleeneStar }
};
actions.clear();
actions.emplace_back(PatternActionType::KleeneStar);
ParserString special_open_p("(?");
ParserString special_close_p(")");
@ -354,8 +354,6 @@ private:
else
throw_exception("Could not parse pattern, unexpected starting symbol");
}
this->actions = std::move(actions);
}
protected:

View File

@ -164,6 +164,12 @@ public:
return buf;
}
protected:
static constexpr size_t getStackThreshold()
{
return 0;
}
};
@ -209,6 +215,12 @@ public:
memcpy(new_buf, buf, old_size);
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;
}
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:
using value_type = T;
@ -130,55 +141,46 @@ public:
PODArray() {}
PODArray(size_t n)
PODArray(size_t n)
{
alloc_for_num_elements(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);
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);
insert(from_begin, from_end);
}
~PODArray()
~PODArray()
{
dealloc();
}
PODArray(PODArray && other)
{
c_start = other.c_start;
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;
this->swap(other);
}
PODArray & operator=(PODArray && other)
{
std::swap(c_start, other.c_start);
std::swap(c_end, other.c_end);
std::swap(c_end_of_storage, other.c_end_of_storage);
this->swap(other);
return *this;
}
T * data() { return t_start(); }
const T * data() const { return t_start(); }
size_t size() 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 size() 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(); }
T & operator[] (size_t n) { return t_start()[n]; }
const T & operator[] (size_t n) const { return t_start()[n]; }
@ -310,9 +312,107 @@ public:
void swap(PODArray & rhs)
{
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);
/// Swap two PODArray objects, arr1 and arr2, that satisfy the following conditions:
/// - The elements of arr1 are stored on stack.
/// - 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)
@ -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-регистр по адресу последнего элемента. */
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)
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;
}