susumu.yata
null+****@clear*****
Mon Dec 10 15:30:14 JST 2012
susumu.yata 2012-12-10 15:30:14 +0900 (Mon, 10 Dec 2012) New Revision: d93033e31adc1c614501c81563a291d1cb8ca5ad https://github.com/groonga/grnxx/commit/d93033e31adc1c614501c81563a291d1cb8ca5ad Log: Update the interface of grnxx::alpha::BlobVector. Modified files: lib/alpha/blob_vector.cpp lib/alpha/blob_vector.hpp test/test_alpha_blob_vector.cpp Modified: lib/alpha/blob_vector.cpp (+24 -40) =================================================================== --- lib/alpha/blob_vector.cpp 2012-12-10 13:02:01 +0900 (8fc2c81) +++ lib/alpha/blob_vector.cpp 2012-12-10 15:30:14 +0900 (010eabb) @@ -73,22 +73,14 @@ std::unique_ptr<BlobVectorImpl> BlobVectorImpl::open(io::Pool pool, return vector; } -const void *BlobVectorImpl::get_value(uint64_t id, uint64_t *length) { +Blob BlobVectorImpl::get_value(uint64_t id) { const BlobVectorCell cell = table_[id]; switch (cell.type()) { case BLOB_VECTOR_NULL: { - if (length) { - *length = 0; - } - return nullptr; + return Blob(nullptr); } case BLOB_VECTOR_SMALL: { - if (length) { - *length = cell.small_length(); - } - // FIXME: The cell might be updated by other threads and processes. - // This interface cannot solve this problem. - return table_[id].value(); + return Blob(cell); } case BLOB_VECTOR_MEDIUM: { if (!value_store_) { @@ -97,19 +89,12 @@ const void *BlobVectorImpl::get_value(uint64_t id, uint64_t *length) { value_store_.open(pool_, header_->value_store_block_id()); } } - if (length) { - *length = cell.medium_length(); - } - return &value_store_[cell.offset()]; + return Blob(&value_store_[cell.offset()], cell.medium_length()); } case BLOB_VECTOR_LARGE: { - const BlobVectorValueHeader *value_header = - static_cast<const BlobVectorValueHeader *>( - pool_.get_block_address(cell.block_id())); - if (length) { - *length = value_header->length(); - } - return value_header + 1; + const auto value_header = static_cast<const BlobVectorValueHeader *>( + pool_.get_block_address(cell.block_id())); + return Blob(value_header + 1, value_header->length()); } default: { GRNXX_ERROR() << "invalid value type"; @@ -118,17 +103,18 @@ const void *BlobVectorImpl::get_value(uint64_t id, uint64_t *length) { } } -void BlobVectorImpl::set_value(uint64_t id, const void *ptr, uint64_t length) { +void BlobVectorImpl::set_value(uint64_t id, const Blob &value) { BlobVectorCell new_cell; - if (!ptr) { + if (!value) { new_cell = BlobVectorCell::null_value_cell(); } else { - if (length < BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH) { - new_cell = BlobVectorCell::small_value_cell(ptr, length); - } else if (length < BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH) { - new_cell = create_medium_value(ptr, length); + if (value.length() < BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH) { + new_cell = BlobVectorCell::small_value_cell(value.address(), + value.length()); + } else if (value.length() < BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH) { + new_cell = create_medium_value(value); } else { - new_cell = create_large_value(ptr, length); + new_cell = create_large_value(value); } } @@ -223,8 +209,7 @@ void BlobVectorImpl::open_vector(io::Pool pool, uint32_t block_id) { table_.open(pool, header_->table_block_id()); } -BlobVectorCell BlobVectorImpl::create_medium_value(const void *ptr, - uint64_t length) { +BlobVectorCell BlobVectorImpl::create_medium_value(const Blob &value) { Lock lock(mutable_inter_thread_mutex()); if (!value_store_) { @@ -263,7 +248,7 @@ BlobVectorCell BlobVectorImpl::create_medium_value(const void *ptr, BLOB_VECTOR_VALUE_STORE_PAGE_SIZE - offset_in_page; // Reserve a new page if there is not enough space in the current page. - if (length > size_left_in_page) { + if (value.length() > size_left_in_page) { if (offset != 0) { // Freeze the current page if it is empty. const uint32_t page_id = static_cast<uint32_t>( @@ -283,26 +268,25 @@ BlobVectorCell BlobVectorImpl::create_medium_value(const void *ptr, } index_store_[page_id].set_num_values(0); } - header_->set_next_value_offset(offset + length); + header_->set_next_value_offset(offset + value.length()); - std::memcpy(&value_store_[offset], ptr, length); + std::memcpy(&value_store_[offset], value.address(), value.length()); const uint32_t page_id = static_cast<uint32_t>( offset >> BLOB_VECTOR_VALUE_STORE_PAGE_SIZE_BITS); index_store_[page_id].set_num_values(index_store_[page_id].num_values() + 1); - return BlobVectorCell::medium_value_cell(offset, length); + return BlobVectorCell::medium_value_cell(offset, value.length()); } -BlobVectorCell BlobVectorImpl::create_large_value(const void *ptr, - uint64_t length) { +BlobVectorCell BlobVectorImpl::create_large_value(const Blob &value) { const io::BlockInfo *block_info = - pool_.create_block(sizeof(BlobVectorValueHeader) + length); + pool_.create_block(sizeof(BlobVectorValueHeader) + value.length()); BlobVectorValueHeader *value_header = static_cast<BlobVectorValueHeader *>( pool_.get_block_address(*block_info)); - value_header->set_length(length); - std::memcpy(value_header + 1, ptr, length); + value_header->set_length(value.length()); + std::memcpy(value_header + 1, value.address(), value.length()); register_large_value(block_info->id(), value_header); return BlobVectorCell::large_value_cell(block_info->id()); } Modified: lib/alpha/blob_vector.hpp (+111 -11) =================================================================== --- lib/alpha/blob_vector.hpp 2012-12-10 13:02:01 +0900 (346a015) +++ lib/alpha/blob_vector.hpp 2012-12-10 15:30:14 +0900 (7697226) @@ -271,6 +271,87 @@ class BlobVectorCell { static_assert(sizeof(BlobVectorCell) == sizeof(uint64_t), "sizeof(BlobVectorCell) != sizeof(uint64_t)"); +class Blob { + public: + Blob() + : address_(nullptr), length_(0), + cell_(BlobVectorCell::null_value_cell()) {} + explicit Blob(std::nullptr_t) + : address_(nullptr), length_(0), + cell_(BlobVectorCell::null_value_cell()) {} + Blob(const void *address, uint64_t length) + : address_(address), length_(length), cell_() {} + explicit Blob(BlobVectorCell small_value_cell) + : address_(), length_(), cell_(small_value_cell) { + address_ = cell_.value(); + length_ = cell_.small_length(); + } + + // Note: address_ refers to the own value if it is small. + Blob(const Blob &rhs) : address_(), length_(rhs.length_), cell_(rhs.cell_) { + if (cell_.type() == BLOB_VECTOR_SMALL) { + address_ = cell_.value(); + } else { + address_ = rhs.address_; + } + } + Blob &operator=(const Blob &rhs) { + length_ = rhs.length_; + cell_ = rhs.cell_; + if (cell_.type() == BLOB_VECTOR_SMALL) { + address_ = cell_.value(); + } else { + address_ = rhs.address_; + } + return *this; + } + + Blob &operator=(std::nullptr_t) { + return *this = Blob(nullptr); + } + + explicit operator bool() const { + return static_cast<bool>(address_); + } + + const void *address() const { + return address_; + } + uint64_t length() const { + return length_; + } + + void set_address(const void *value) { + address_ = value; + } + void set_length(uint64_t value) { + length_ = value; + } + + private: + const void *address_; + uint64_t length_; + BlobVectorCell cell_; +}; + +class BlobVector; + +class BlobRef { + public: + BlobRef(BlobVector *vector, uint64_t id) : vector_(vector), id_(id) {} + + // vector_->get_value(id_); + operator Blob() const; + + // vector_->set_value(id_, value); + BlobRef &operator=(std::nullptr_t); + BlobRef &operator=(const Blob &value); + + private: + BlobVector *vector_; + uint64_t id_; +}; + typedef Vector<BlobVectorCell> BlobVectorTable; typedef Vector<char, BLOB_VECTOR_VALUE_STORE_PAGE_SIZE, @@ -289,10 +370,8 @@ class BlobVectorImpl { static std::unique_ptr<BlobVectorImpl> open(io::Pool pool, uint32_t block_id); - const void *get_value(uint64_t id, uint64_t *length); - void set_value(uint64_t id, const void *ptr, uint64_t length); - - // TODO + Blob get_value(uint64_t id); + void set_value(uint64_t id, const Blob &value); uint32_t block_id() const { return block_info_->id(); @@ -317,8 +396,8 @@ class BlobVectorImpl { void create_vector(io::Pool pool); void open_vector(io::Pool pool, uint32_t block_id); - BlobVectorCell create_medium_value(const void *ptr, uint64_t length); - BlobVectorCell create_large_value(const void *ptr, uint64_t length); + BlobVectorCell create_medium_value(const Blob &value); + BlobVectorCell create_large_value(const Blob &value); void free_value(BlobVectorCell cell); @@ -363,14 +442,21 @@ class BlobVector { *this = BlobVector(); } - // TODO -// BlobVectorValueRef operator[](uint64_t id); + BlobRef operator[](uint64_t id) { + return BlobRef(this, id); + } - const void *get_value(uint64_t id, uint64_t *length = nullptr) { - return impl_->get_value(id, length); + Blob get_value(uint64_t id) { + return impl_->get_value(id); + } + void set_value(uint64_t id, std::nullptr_t) { + impl_->set_value(id, Blob(nullptr)); + } + void set_value(uint64_t id, const Blob &value) { + impl_->set_value(id, value); } void set_value(uint64_t id, const void *ptr, uint64_t length) { - impl_->set_value(id, ptr, length); + impl_->set_value(id, Blob(ptr, length)); } uint32_t block_id() const { @@ -406,6 +492,20 @@ inline StringBuilder &operator<<(StringBuilder &builder, return vector.write_to(builder); } +inline BlobRef::operator Blob() const { + return vector_->get_value(id_); +} + +inline BlobRef &BlobRef::operator=(std::nullptr_t) { + vector_->set_value(id_, nullptr); + return *this; +} + +inline BlobRef &BlobRef::operator=(const Blob &value) { + vector_->set_value(id_, value); + return *this; +} + } // namespace alpha } // namespace grnxx Modified: test/test_alpha_blob_vector.cpp (+68 -59) =================================================================== --- test/test_alpha_blob_vector.cpp 2012-12-10 13:02:01 +0900 (75cc538) +++ test/test_alpha_blob_vector.cpp 2012-12-10 15:30:14 +0900 (ca86216) @@ -56,23 +56,23 @@ void test_basics() { vector.set_value(1000000000, values[3].c_str(), values[3].length()); vector.set_value(1000000000000ULL, values[4].c_str(), values[4].length()); - std::uint64_t length = 0; - - assert(std::memcmp(vector.get_value(0, &length), - values[0].c_str(), values[0].length()) == 0); - assert(length == values[0].length()); - assert(std::memcmp(vector.get_value(1000, &length), - values[1].c_str(), values[1].length()) == 0); - assert(length == values[1].length()); - assert(std::memcmp(vector.get_value(1000000, &length), - values[2].c_str(), values[2].length()) == 0); - assert(length == values[2].length()); - assert(std::memcmp(vector.get_value(1000000000, &length), - values[3].c_str(), values[3].length()) == 0); - assert(length == values[3].length()); - assert(std::memcmp(vector.get_value(1000000000000ULL, &length), - values[4].c_str(), values[4].length()) == 0); - assert(length == values[4].length()); + grnxx::alpha::Blob blob; + + assert(blob = vector[0]); + assert(blob.length() == values[0].length()); + assert(std::memcmp(blob.address(), values[0].c_str(), blob.length()) == 0); + assert(blob = vector[1000]); + assert(blob.length() == values[1].length()); + assert(std::memcmp(blob.address(), values[1].c_str(), blob.length()) == 0); + assert(blob = vector[1000000]); + assert(blob.length() == values[2].length()); + assert(std::memcmp(blob.address(), values[2].c_str(), blob.length()) == 0); + assert(blob = vector[1000000000]); + assert(blob.length() == values[3].length()); + assert(std::memcmp(blob.address(), values[3].c_str(), blob.length()) == 0); + assert(blob = vector[1000000000000ULL]); + assert(blob.length() == values[4].length()); + assert(std::memcmp(blob.address(), values[4].c_str(), blob.length()) == 0); std::uint32_t block_id = vector.block_id(); @@ -84,24 +84,37 @@ void test_basics() { GRNXX_NOTICE() << "blob_vector = " << vector; - assert(std::memcmp(vector.get_value(0, &length), - values[0].c_str(), values[0].length()) == 0); - assert(length == values[0].length()); - assert(std::memcmp(vector.get_value(1000, &length), - values[1].c_str(), values[1].length()) == 0); - assert(length == values[1].length()); - assert(std::memcmp(vector.get_value(1000000, &length), - values[2].c_str(), values[2].length()) == 0); - assert(length == values[2].length()); - assert(std::memcmp(vector.get_value(1000000000, &length), - values[3].c_str(), values[3].length()) == 0); - assert(length == values[3].length()); - assert(std::memcmp(vector.get_value(1000000000000ULL, &length), - values[4].c_str(), values[4].length()) == 0); - assert(length == values[4].length()); - - vector.set_value(0, nullptr, 0); - assert(!vector.get_value(0)); + assert(blob = vector[0]); + assert(blob.length() == values[0].length()); + assert(std::memcmp(blob.address(), values[0].c_str(), blob.length()) == 0); + assert(blob = vector[1000]); + assert(blob.length() == values[1].length()); + assert(std::memcmp(blob.address(), values[1].c_str(), blob.length()) == 0); + assert(blob = vector[1000000]); + assert(blob.length() == values[2].length()); + assert(std::memcmp(blob.address(), values[2].c_str(), blob.length()) == 0); + assert(blob = vector[1000000000]); + assert(blob.length() == values[3].length()); + assert(std::memcmp(blob.address(), values[3].c_str(), blob.length()) == 0); + assert(blob = vector[1000000000000ULL]); + assert(blob.length() == values[4].length()); + assert(std::memcmp(blob.address(), values[4].c_str(), blob.length()) == 0); + + vector[0] = grnxx::alpha::Blob("banana", 6); + blob = vector[0]; + assert(blob); + assert(blob.length() == 6); + assert(std::memcmp(blob.address(), "banana", 6) == 0); + + grnxx::alpha::Blob blob2 = blob; + blob = nullptr; + assert(blob2); + assert(blob2.length() == 6); + assert(std::memcmp(blob2.address(), "banana", 6) == 0); + + vector[0] = nullptr; + blob = vector[0]; + assert(!blob); vector.close(); pool.close(); @@ -134,21 +147,19 @@ void test_sequential_access(int num_loops, for (std::size_t i = 0; i < values.size(); ++i) { vector.set_value(i, values[i].c_str(), values[i].length()); - std::uint64_t length; - const char *address = - static_cast<const char *>(vector.get_value(i, &length)); - assert(address); - assert(length == values[i].length()); - assert(std::memcmp(address, values[i].c_str(), length) == 0); + grnxx::alpha::Blob blob = vector[i]; + assert(blob); + assert(blob.length() == values[i].length()); + assert(std::memcmp(blob.address(), values[i].c_str(), + blob.length()) == 0); } for (std::size_t i = 0; i < values.size(); ++i) { - std::uint64_t length; - const char *address = - static_cast<const char *>(vector.get_value(i, &length)); - assert(address); - assert(length == values[i].length()); - assert(std::memcmp(address, values[i].c_str(), length) == 0); + grnxx::alpha::Blob blob = vector[i]; + assert(blob); + assert(blob.length() == values[i].length()); + assert(std::memcmp(blob.address(), values[i].c_str(), + blob.length()) == 0); } GRNXX_NOTICE() << "total_size = " << pool.header().total_size(); @@ -186,21 +197,19 @@ void test_random_access(int num_loops, for (std::size_t i = 0; i < values.size(); ++i) { vector.set_value(ids[i], values[i].c_str(), values[i].length()); - std::uint64_t length; - const char *address = - static_cast<const char *>(vector.get_value(ids[i], &length)); - assert(address); - assert(length == values[i].length()); - assert(std::memcmp(address, values[i].c_str(), length) == 0); + grnxx::alpha::Blob blob = vector[ids[i]]; + assert(blob); + assert(blob.length() == values[i].length()); + assert(std::memcmp(blob.address(), values[i].c_str(), + blob.length()) == 0); } for (std::size_t i = 0; i < values.size(); ++i) { - std::uint64_t length; - const char *address = - static_cast<const char *>(vector.get_value(ids[i], &length)); - assert(address); - assert(length == values[i].length()); - assert(std::memcmp(address, values[i].c_str(), length) == 0); + grnxx::alpha::Blob blob = vector[ids[i]]; + assert(blob); + assert(blob.length() == values[i].length()); + assert(std::memcmp(blob.address(), values[i].c_str(), + blob.length()) == 0); } GRNXX_NOTICE() << "total_size = " << pool.header().total_size(); -------------- next part -------------- HTML����������������������������...Download