More strict semantic on sharing columns (development) [#CLICKHOUSE-2].

This commit is contained in:
Alexey Milovidov 2017-12-11 05:59:56 +03:00
parent c3015bece3
commit 524d98c7fc
3 changed files with 156 additions and 0 deletions

89
dbms/src/Common/COWPtr.h Normal file
View File

@ -0,0 +1,89 @@
#pragma once
#include <boost/noncopyable.hpp>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
#include <iostream>
/** Copy-on-write shared ptr.
* Allows to work with shared immutable objects and sometimes unshare and mutate you own unique copy.
*
* Usage:
class Column : public COWPtr<Column>
{
private:
friend class COWPtr<Column>;
Column()
Column(const Column &)
public:
...
}
* It will provide 'create', 'clone' and 'mutate' methods.
*
* 'create' and 'clone' methods creates mutable noncopyable object: you cannot share mutable objects.
* 'mutate' method allows to create mutable noncopyable object from immutable object:
* either by cloning or by using directly, if it is not shared.
* These methods are thread-safe.
*
* Example:
*
Column::Ptr x = Column::create(1);
Column::Ptr y = x;
/// Now x and y are shared.
/// Change value of x.
{
Column::MutablePtr mutate_x = x->mutate();
mutate_x->set(2);
x = std::move(mutate_x);
}
/// Now x and y are unshared and have different values.
*/
template <typename Derived>
class COWPtr : public boost::intrusive_ref_counter<Derived>
{
private:
Derived * derived() { return static_cast<Derived *>(this); }
const Derived * derived() const { return static_cast<const Derived *>(this); }
public:
template <typename T> class noncopyable : public T, private boost::noncopyable { using T::T; };
template <typename T> class immutable_ptr : public boost::intrusive_ptr<const T>
{
public:
template <typename U>
immutable_ptr(const boost::intrusive_ptr<const U> & other) : boost::intrusive_ptr<const U>(other) {}
template <typename U>
immutable_ptr(const boost::intrusive_ptr<U> && other) : boost::intrusive_ptr<const U>(std::move(other)) {}
template <typename U>
immutable_ptr(const boost::intrusive_ptr<U> &) = delete;
};
using Ptr = immutable_ptr<Derived>;
using MutablePtr = noncopyable<boost::intrusive_ptr<Derived>>;
template <typename... Args>
static MutablePtr create(Args &&... args) { return new Derived(std::forward<Args>(args)...); }
Ptr getPtr() const { return static_cast<Ptr>(derived()); }
MutablePtr getPtr() { return static_cast<MutablePtr>(derived()); }
MutablePtr clone() const { return new Derived(*derived()); }
MutablePtr mutate() const
{
if (this->use_count() > 1)
return clone();
else
return const_cast<COWPtr*>(this)->getPtr();
}
};

View File

@ -65,3 +65,6 @@ target_link_libraries (integer_hash_tables_and_hashes clickhouse_common_io)
add_executable (allocator allocator.cpp)
target_link_libraries (allocator clickhouse_common_io)
add_executable (cow_columns cow_columns.cpp)
target_link_libraries (cow_columns clickhouse_common_io)

View File

@ -0,0 +1,64 @@
#include <Common/COWPtr.h>
#include <iostream>
class Column : public COWPtr<Column>
{
private:
friend class COWPtr<Column>;
int data;
Column(int data) : data(data) {}
public:
int get() const { return data; }
void set(int value) { data = value; }
};
using ColumnPtr = Column::Ptr;
using MutableColumnPtr = Column::MutablePtr;
int main(int, char **)
{
ColumnPtr x = Column::create(1);
ColumnPtr y = x;
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
std::cerr << "addresses: " << &*x << ", " << &*y << "\n";
{
MutableColumnPtr mutable_y = y->mutate();
mutable_y->set(2);
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mutable_y->use_count() << "\n";
std::cerr << "addresses: " << &*x << ", " << &*y << ", " << &*mutable_y << "\n";
y = std::move(mutable_y);
}
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
std::cerr << "addresses: " << &*x << ", " << &*y << "\n";
x = Column::create(0);
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
std::cerr << "addresses: " << &*x << ", " << &*y << "\n";
{
MutableColumnPtr mutable_y = y->mutate();
mutable_y->set(3);
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << ", " << mutable_y->use_count() << "\n";
std::cerr << "addresses: " << &*x << ", " << &*y << ", " << &*mutable_y << "\n";
y = std::move(mutable_y);
}
std::cerr << "values: " << x->get() << ", " << y->get() << "\n";
std::cerr << "refcounts: " << x->use_count() << ", " << y->use_count() << "\n";
return 0;
}