susumu.yata
null+****@clear*****
Wed Dec 12 11:09:35 JST 2012
susumu.yata 2012-12-12 11:09:35 +0900 (Wed, 12 Dec 2012) New Revision: c8cf5ec2e2afb0d32a9555cdc2daf997cc87b9a5 https://github.com/groonga/grnxx/commit/c8cf5ec2e2afb0d32a9555cdc2daf997cc87b9a5 Log: Implement grnxx::alpha::BlobVector::append/prepend(). Modified files: lib/alpha/blob_vector.cpp lib/alpha/blob_vector.hpp Modified: lib/alpha/blob_vector.cpp (+122 -62) =================================================================== --- lib/alpha/blob_vector.cpp 2012-12-11 19:12:12 +0900 (3bc9adc) +++ lib/alpha/blob_vector.cpp 2012-12-12 11:09:35 +0900 (f25f9eb) @@ -73,70 +73,60 @@ std::unique_ptr<BlobVectorImpl> BlobVectorImpl::open(io::Pool pool, return vector; } -Blob BlobVectorImpl::get_value(uint64_t id) { - const BlobVectorCell cell = table_[id]; - switch (cell.type()) { - case BLOB_VECTOR_NULL: { - return Blob(nullptr); - } - case BLOB_VECTOR_SMALL: { - return Blob(cell); - } - case BLOB_VECTOR_MEDIUM: { - if (!value_store_) { - Lock lock(mutable_inter_thread_mutex()); - if (!value_store_) { - value_store_.open(pool_, header_->value_store_block_id()); - } - } - return Blob(&value_store_[cell.offset()], cell.medium_length()); - } - case BLOB_VECTOR_LARGE: { - 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"; - GRNXX_THROW(); - } - } -} - void BlobVectorImpl::set_value(uint64_t id, const Blob &value) { - BlobVectorCell new_cell; - if (!value) { - new_cell = BlobVectorCell::null_value_cell(); - } else { - 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(value); - } - } - - // The old cell is replaced with the new cell. + const BlobVectorCell new_cell = create_value(value); BlobVectorCell old_cell; try { do { old_cell = table_[id]; } while (!atomic_compare_and_swap(old_cell, new_cell, &table_[id])); } catch (...) { + // The new value is freed on failure. free_value(new_cell); throw; } + // The old value is freed on success. free_value(old_cell); } void BlobVectorImpl::append(uint64_t id, const Blob &value) { - // TODO + if (!value || (value.length() == 0)) { + return; + } + + for ( ; ; ) { + const BlobVectorCell old_cell = table_[id]; + const Blob old_value = get_value(old_cell); + const BlobVectorCell new_cell = join_values(old_value, value); + if (atomic_compare_and_swap(old_cell, new_cell, &table_[id])) { + // The old value is freed on success. + free_value(old_cell); + break; + } else { + // The new value is freed on failure. + free_value(new_cell); + } + } } void BlobVectorImpl::prepend(uint64_t id, const Blob &value) { - // TODO + if (!value || (value.length() == 0)) { + return; + } + + for ( ; ; ) { + const BlobVectorCell old_cell = table_[id]; + const Blob old_value = get_value(old_cell); + const BlobVectorCell new_cell = join_values(value, old_value); + if (atomic_compare_and_swap(old_cell, new_cell, &table_[id])) { + // The old value is freed on success. + free_value(old_cell); + break; + } else { + // The new value is freed on failure. + free_value(new_cell); + } + } } StringBuilder &BlobVectorImpl::write_to(StringBuilder &builder) const { @@ -184,7 +174,7 @@ void BlobVectorImpl::create_vector(io::Pool pool) { block_info_ = pool.create_block(sizeof(BlobVectorHeader)); try { - table_.create(pool_, BlobVectorCell()); + table_.create(pool_, BlobVectorCell::null_value()); } catch (...) { pool_.free_block(*block_info_); throw; @@ -217,7 +207,78 @@ void BlobVectorImpl::open_vector(io::Pool pool, uint32_t block_id) { table_.open(pool, header_->table_block_id()); } -BlobVectorCell BlobVectorImpl::create_medium_value(const Blob &value) { +Blob BlobVectorImpl::get_value(BlobVectorCell cell) { + switch (cell.type()) { + case BLOB_VECTOR_NULL: { + return Blob(nullptr); + } + case BLOB_VECTOR_SMALL: { + return Blob(cell); + } + case BLOB_VECTOR_MEDIUM: { + if (!value_store_) { + Lock lock(mutable_inter_thread_mutex()); + if (!value_store_) { + value_store_.open(pool_, header_->value_store_block_id()); + } + } + return Blob(&value_store_[cell.offset()], cell.medium_length()); + } + case BLOB_VECTOR_LARGE: { + 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"; + GRNXX_THROW(); + } + } +} + +BlobVectorCell BlobVectorImpl::create_value(const Blob &value) { + if (!value) { + return BlobVectorCell::null_value(); + } + + BlobVectorCell cell; + void *address; + if (value.length() < BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH) { + address = create_small_value(value.length(), &cell); + } else if (value.length() < BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH) { + address = create_medium_value(value.length(), &cell); + } else { + address = create_large_value(value.length(), &cell); + } + std::memcpy(address, value.address(), value.length()); + return cell; +} + +BlobVectorCell BlobVectorImpl::join_values(const Blob &lhs, const Blob &rhs) { + const uint64_t length = lhs.length() + rhs.length(); + BlobVectorCell cell; + void *address; + if (length < BLOB_VECTOR_MEDIUM_VALUE_MIN_LENGTH) { + address = create_small_value(length, &cell); + } else if (length < BLOB_VECTOR_LARGE_VALUE_MIN_LENGTH) { + address = create_medium_value(length, &cell); + } else { + address = create_large_value(length, &cell); + } + std::memcpy(address, lhs.address(), lhs.length()); + std::memcpy(static_cast<char *>(address) + lhs.length(), + rhs.address(), rhs.length()); + return cell; +} + +void *BlobVectorImpl::create_small_value(uint64_t length, + BlobVectorCell *cell) { + *cell = BlobVectorCell::small_value(length); + return cell->value(); +} + +void *BlobVectorImpl::create_medium_value(uint64_t length, + BlobVectorCell *cell) { Lock lock(mutable_inter_thread_mutex()); if (!value_store_) { @@ -256,7 +317,7 @@ BlobVectorCell BlobVectorImpl::create_medium_value(const Blob &value) { BLOB_VECTOR_VALUE_STORE_PAGE_SIZE - offset_in_page; // Reserve a new page if there is not enough space in the current page. - if (value.length() > size_left_in_page) { + if (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>( @@ -276,27 +337,26 @@ BlobVectorCell BlobVectorImpl::create_medium_value(const Blob &value) { } index_store_[page_id].set_num_values(0); } - header_->set_next_value_offset(offset + value.length()); - - std::memcpy(&value_store_[offset], value.address(), value.length()); + header_->set_next_value_offset(offset + 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, value.length()); + *cell = BlobVectorCell::medium_value(offset, length); + return &value_store_[offset]; } -BlobVectorCell BlobVectorImpl::create_large_value(const Blob &value) { +void *BlobVectorImpl::create_large_value(uint64_t length, + BlobVectorCell *cell) { const io::BlockInfo *block_info = - pool_.create_block(sizeof(BlobVectorValueHeader) + value.length()); - BlobVectorValueHeader *value_header = - static_cast<BlobVectorValueHeader *>( - pool_.get_block_address(*block_info)); - value_header->set_length(value.length()); - std::memcpy(value_header + 1, value.address(), value.length()); + pool_.create_block(sizeof(BlobVectorValueHeader) + length); + auto value_header = static_cast<BlobVectorValueHeader *>( + pool_.get_block_address(*block_info)); + value_header->set_length(length); register_large_value(block_info->id(), value_header); - return BlobVectorCell::large_value_cell(block_info->id()); + *cell = BlobVectorCell::large_value(block_info->id()); + return value_header + 1; } void BlobVectorImpl::free_value(BlobVectorCell cell) { Modified: lib/alpha/blob_vector.hpp (+31 -25) =================================================================== --- lib/alpha/blob_vector.hpp 2012-12-11 19:12:12 +0900 (0811359) +++ lib/alpha/blob_vector.hpp 2012-12-12 11:09:35 +0900 (a1b44fb) @@ -198,18 +198,18 @@ const uint8_t BLOB_VECTOR_CELL_FLAGS_MASK = 0xF0; class BlobVectorCell { public: - BlobVectorCell() : qword_(0) {} + BlobVectorCell() = default; + explicit BlobVectorCell(std::nullptr_t) : qword_(0) {} - static BlobVectorCell null_value_cell() { - return BlobVectorCell(); + static BlobVectorCell null_value() { + return BlobVectorCell(nullptr); } - static BlobVectorCell small_value_cell(const void *ptr, uint64_t length) { - BlobVectorCell cell; + static BlobVectorCell small_value(uint64_t length) { + BlobVectorCell cell(nullptr); cell.bytes_[0] = BLOB_VECTOR_SMALL | static_cast<uint8_t>(length); - std::memcpy(&cell.bytes_[1], ptr, length); return cell; } - static BlobVectorCell medium_value_cell(uint64_t offset, uint64_t length) { + static BlobVectorCell medium_value(uint64_t offset, uint64_t length) { BlobVectorCell cell; cell.bytes_[0] = BLOB_VECTOR_MEDIUM | static_cast<uint8_t>(offset >> 40); cell.bytes_[1] = static_cast<uint8_t>(offset >> 32); @@ -217,8 +217,8 @@ class BlobVectorCell { cell.dwords_[1] = static_cast<uint32_t>(offset); return cell; } - static BlobVectorCell large_value_cell(uint32_t block_id) { - BlobVectorCell cell; + static BlobVectorCell large_value(uint32_t block_id) { + BlobVectorCell cell(nullptr); cell.bytes_[0] = BLOB_VECTOR_LARGE; cell.dwords_[1] = block_id; return cell; @@ -237,6 +237,9 @@ class BlobVectorCell { const void *value() const { return &bytes_[1]; } + void *value() { + return &bytes_[1]; + } // Accessors to medium values. uint64_t medium_length() const { @@ -273,12 +276,8 @@ static_assert(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() : address_(nullptr), length_(0), cell_() {} + explicit Blob(std::nullptr_t) : address_(nullptr), length_(0), cell_() {} Blob(const void *address, uint64_t length) : address_(address), length_(length), cell_() {} explicit Blob(BlobVectorCell small_value_cell) @@ -353,11 +352,6 @@ class BlobRef { return *this; } - BlobRef &operator+=(const Blob &value) { - append(value); - return *this; - } - Blob get() const; void set(std::nullptr_t) { set(Blob(nullptr)); @@ -399,7 +393,9 @@ class BlobVectorImpl { static std::unique_ptr<BlobVectorImpl> open(io::Pool pool, uint32_t block_id); - Blob get_value(uint64_t id); + Blob get_value(uint64_t id) { + return get_value(table_[id]); + } void set_value(uint64_t id, const Blob &value); void append(uint64_t id, const Blob &value); @@ -428,8 +424,14 @@ class BlobVectorImpl { void create_vector(io::Pool pool); void open_vector(io::Pool pool, uint32_t block_id); - BlobVectorCell create_medium_value(const Blob &value); - BlobVectorCell create_large_value(const Blob &value); + Blob get_value(BlobVectorCell cell); + + BlobVectorCell create_value(const Blob &value); + BlobVectorCell join_values(const Blob &lhs, const Blob &rhs); + + void *create_small_value(uint64_t length, BlobVectorCell *cell); + void *create_medium_value(uint64_t length, BlobVectorCell *cell); + void *create_large_value(uint64_t length, BlobVectorCell *cell); void free_value(BlobVectorCell cell); @@ -485,8 +487,12 @@ class BlobVector { impl_->set_value(id, value); } - void append(uint64_t id, const Blob &value); - void prepend(uint64_t id, const Blob &value); + void append(uint64_t id, const Blob &value) { + impl_->append(id, value); + } + void prepend(uint64_t id, const Blob &value) { + impl_->prepend(id, value); + } uint32_t block_id() const { return impl_->block_id(); -------------- next part -------------- HTML����������������������������... Télécharger