mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-22 01:30:51 +00:00
More strict semantic on sharing columns (development) [#CLICKHOUSE-2].
This commit is contained in:
parent
c3015bece3
commit
524d98c7fc
89
dbms/src/Common/COWPtr.h
Normal file
89
dbms/src/Common/COWPtr.h
Normal 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();
|
||||
}
|
||||
};
|
@ -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)
|
||||
|
64
dbms/src/Common/tests/cow_columns.cpp
Normal file
64
dbms/src/Common/tests/cow_columns.cpp
Normal 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user