2011-12-30 17:57:02 +00:00
|
|
|
|
#pragma once
|
2011-06-27 18:22:14 +00:00
|
|
|
|
|
2012-06-22 16:54:51 +00:00
|
|
|
|
#include <boost/noncopyable.hpp>
|
2011-06-27 18:22:14 +00:00
|
|
|
|
|
2014-01-04 04:53:07 +00:00
|
|
|
|
#include <DB/Common/ProfileEvents.h>
|
2015-08-16 13:00:22 +00:00
|
|
|
|
#include <DB/Common/Allocator.h>
|
2014-01-04 04:53:07 +00:00
|
|
|
|
|
2013-10-13 06:53:11 +00:00
|
|
|
|
#include <DB/Core/Exception.h>
|
|
|
|
|
#include <DB/Core/ErrorCodes.h>
|
2015-04-12 04:39:20 +00:00
|
|
|
|
#include <DB/Core/Defines.h>
|
2011-06-27 18:22:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
2013-09-08 05:53:10 +00:00
|
|
|
|
/** Замена std::vector<char> для использования в буферах.
|
|
|
|
|
* Отличается тем, что не делает лишний memset. (И почти ничего не делает.)
|
2013-10-13 06:53:11 +00:00
|
|
|
|
* Также можно попросить выделять выровненный кусок памяти.
|
2013-09-08 05:53:10 +00:00
|
|
|
|
*/
|
2015-08-16 13:00:22 +00:00
|
|
|
|
struct Memory : boost::noncopyable, Allocator
|
2012-06-21 18:43:29 +00:00
|
|
|
|
{
|
2014-03-13 20:12:40 +00:00
|
|
|
|
size_t m_capacity = 0;
|
|
|
|
|
size_t m_size = 0;
|
|
|
|
|
char * m_data = nullptr;
|
|
|
|
|
size_t alignment = 0;
|
2013-10-13 06:53:11 +00:00
|
|
|
|
|
2014-03-13 20:12:40 +00:00
|
|
|
|
Memory() {}
|
2012-06-21 18:43:29 +00:00
|
|
|
|
|
2013-10-13 06:53:11 +00:00
|
|
|
|
/// Если alignment != 0, то будет выделяться память, выровненная на alignment.
|
|
|
|
|
Memory(size_t size_, size_t alignment_ = 0) : m_capacity(size_), m_size(m_capacity), alignment(alignment_)
|
|
|
|
|
{
|
|
|
|
|
alloc();
|
|
|
|
|
}
|
2012-06-21 18:43:29 +00:00
|
|
|
|
|
2013-09-08 05:53:10 +00:00
|
|
|
|
~Memory()
|
|
|
|
|
{
|
2013-10-13 06:53:11 +00:00
|
|
|
|
dealloc();
|
2013-09-08 05:53:10 +00:00
|
|
|
|
}
|
2012-06-21 18:43:29 +00:00
|
|
|
|
|
2014-03-13 20:12:40 +00:00
|
|
|
|
Memory(Memory && rhs)
|
|
|
|
|
{
|
|
|
|
|
*this = std::move(rhs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Memory & operator=(Memory && rhs)
|
|
|
|
|
{
|
|
|
|
|
std::swap(m_capacity, rhs.m_capacity);
|
|
|
|
|
std::swap(m_size, rhs.m_size);
|
|
|
|
|
std::swap(m_data, rhs.m_data);
|
|
|
|
|
std::swap(alignment, rhs.alignment);
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-08 05:53:10 +00:00
|
|
|
|
size_t size() const { return m_size; }
|
|
|
|
|
const char & operator[](size_t i) const { return m_data[i]; }
|
|
|
|
|
char & operator[](size_t i) { return m_data[i]; }
|
2012-06-21 18:43:29 +00:00
|
|
|
|
|
2013-09-08 05:53:10 +00:00
|
|
|
|
void resize(size_t new_size)
|
|
|
|
|
{
|
2015-09-01 15:08:37 +00:00
|
|
|
|
if (0 == m_capacity)
|
|
|
|
|
{
|
|
|
|
|
m_size = m_capacity = new_size;
|
|
|
|
|
alloc();
|
|
|
|
|
}
|
|
|
|
|
else if (new_size < m_capacity)
|
2012-06-21 18:43:29 +00:00
|
|
|
|
{
|
2013-09-08 05:53:10 +00:00
|
|
|
|
m_size = new_size;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-08-31 16:49:09 +00:00
|
|
|
|
new_size = align(new_size, alignment);
|
|
|
|
|
/// @todo pointer to void can be converted to pointer to any type with static_cast by ISO C++, reinterpret_cast has no advantages
|
2015-08-16 13:00:22 +00:00
|
|
|
|
m_data = reinterpret_cast<char *>(Allocator::realloc(m_data, m_capacity, new_size, alignment));
|
2013-09-08 05:53:10 +00:00
|
|
|
|
m_capacity = new_size;
|
|
|
|
|
m_size = m_capacity;
|
2013-10-13 06:53:11 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-31 16:49:09 +00:00
|
|
|
|
static size_t align(const size_t value, const size_t alignment)
|
2015-08-16 13:00:22 +00:00
|
|
|
|
{
|
|
|
|
|
if (!alignment)
|
|
|
|
|
return value;
|
|
|
|
|
|
|
|
|
|
return (value + alignment - 1) / alignment * alignment;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-31 16:49:09 +00:00
|
|
|
|
private:
|
2013-10-13 06:53:11 +00:00
|
|
|
|
void alloc()
|
|
|
|
|
{
|
|
|
|
|
if (!m_capacity)
|
|
|
|
|
{
|
2014-04-08 07:31:51 +00:00
|
|
|
|
m_data = nullptr;
|
2013-10-13 06:53:11 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-04 04:53:07 +00:00
|
|
|
|
ProfileEvents::increment(ProfileEvents::IOBufferAllocs);
|
|
|
|
|
ProfileEvents::increment(ProfileEvents::IOBufferAllocBytes, m_capacity);
|
|
|
|
|
|
2015-08-31 16:49:09 +00:00
|
|
|
|
size_t new_capacity = align(m_capacity, alignment);
|
|
|
|
|
/// @todo pointer to void can be converted to pointer to any type with static_cast by ISO C++, reinterpret_cast has no advantages
|
2015-08-16 13:00:22 +00:00
|
|
|
|
m_data = reinterpret_cast<char *>(Allocator::alloc(new_capacity, alignment));
|
|
|
|
|
m_capacity = new_capacity;
|
2015-04-10 17:51:39 +00:00
|
|
|
|
m_size = m_capacity;
|
2013-10-13 06:53:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dealloc()
|
|
|
|
|
{
|
2014-05-03 22:57:43 +00:00
|
|
|
|
if (!m_data)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-08-31 15:49:47 +00:00
|
|
|
|
/// @todo pointer to any type can be implicitly converted to pointer to void, no cast required
|
2015-08-16 13:00:22 +00:00
|
|
|
|
Allocator::free(reinterpret_cast<void *>(m_data), m_capacity);
|
2015-03-06 21:07:21 +00:00
|
|
|
|
m_data = nullptr; /// Чтобы избежать double free, если последующий вызов alloc кинет исключение.
|
2013-09-08 05:53:10 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
2012-06-21 18:43:29 +00:00
|
|
|
|
|
|
|
|
|
|
2013-06-15 04:44:19 +00:00
|
|
|
|
/** Буфер, который может сам владеть своим куском памяти для работы.
|
2011-06-27 18:22:14 +00:00
|
|
|
|
* Аргумент шаблона - ReadBuffer или WriteBuffer
|
|
|
|
|
*/
|
|
|
|
|
template <typename Base>
|
|
|
|
|
class BufferWithOwnMemory : public Base
|
|
|
|
|
{
|
|
|
|
|
protected:
|
2013-09-08 05:53:10 +00:00
|
|
|
|
Memory memory;
|
2011-06-27 18:22:14 +00:00
|
|
|
|
public:
|
2013-06-15 04:44:19 +00:00
|
|
|
|
/// Если передать не-NULL existing_memory, то буфер не будет создавать свой кусок памяти, а будет использовать существующий (и не будет им владеть).
|
2014-04-08 07:58:53 +00:00
|
|
|
|
BufferWithOwnMemory(size_t size = DBMS_DEFAULT_BUFFER_SIZE, char * existing_memory = nullptr, size_t alignment = 0) : Base(nullptr, 0), memory(existing_memory ? 0 : size, alignment)
|
2011-06-27 18:22:14 +00:00
|
|
|
|
{
|
2013-06-15 04:44:19 +00:00
|
|
|
|
Base::set(existing_memory ? existing_memory : &memory[0], size);
|
2011-06-27 18:22:14 +00:00
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|