[Groonga-commit] groonga/grnxx [master] Implement grnxx::alpha::BlobVector::append/prepend().

Back to archive index

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 



More information about the Groonga-commit mailing list
Back to archive index