susumu.yata
null+****@clear*****
Wed Jul 24 12:23:48 JST 2013
susumu.yata 2013-07-24 12:23:48 +0900 (Wed, 24 Jul 2013) New Revision: 871642ffbe4dd72bc00b43517f57e1fe43e23485 https://github.com/groonga/grnxx/commit/871642ffbe4dd72bc00b43517f57e1fe43e23485 Message: Add a prototype of grnxx::map::KeyPool. Added files: lib/grnxx/map/key_pool.cpp lib/grnxx/map/key_pool.hpp Modified files: lib/grnxx/map/Makefile.am Modified: lib/grnxx/map/Makefile.am (+2 -0) =================================================================== --- lib/grnxx/map/Makefile.am 2013-07-24 10:37:29 +0900 (a662804) +++ lib/grnxx/map/Makefile.am 2013-07-24 12:23:48 +0900 (0bd219e) @@ -18,6 +18,7 @@ libgrnxx_map_la_SOURCES = \ cursor_impl.cpp \ double_array.cpp \ hash_table.cpp \ + key_pool.cpp \ key_store.cpp \ patricia.cpp \ scanner_impl.cpp @@ -34,6 +35,7 @@ libgrnxx_map_include_HEADERS = \ hash_table.hpp \ header.hpp \ helper.hpp \ + key_pool.hpp \ key_store.hpp \ patricia.hpp \ scanner_impl.hpp Added: lib/grnxx/map/key_pool.cpp (+397 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/map/key_pool.cpp 2013-07-24 12:23:48 +0900 (82fec2b) @@ -0,0 +1,397 @@ +/* + Copyright (C) 2012-2013 Brazil, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "grnxx/map/key_pool.hpp" + +#include "grnxx/common_header.hpp" +#include "grnxx/exception.hpp" +#include "grnxx/geo_point.hpp" +#include "grnxx/intrinsic.hpp" +#include "grnxx/logger.hpp" +#include "grnxx/map.hpp" +#include "grnxx/storage.hpp" + +namespace grnxx { +namespace map { +namespace { + +constexpr char FORMAT_STRING[] = "grnxx::map::KeyPool"; + +constexpr uint64_t INVALID_UNIT_ID = ~0ULL; +constexpr uint64_t INVALID_ENTRY_ID = (1ULL << 63) - 1; + +} // namespace + +struct KeyPoolHeader { + grnxx::CommonHeader common_header; + int64_t max_key_id; + uint64_t num_keys; + // For other than Bytes. + uint64_t latest_available_unit_id; + uint32_t keys_storage_node_id; + uint32_t bits_storage_node_id; + uint32_t links_storage_node_id; + // For Bytes. + uint64_t latest_free_entry_id; + uint32_t pool_storage_node_id; + uint32_t entries_storage_node_id; + + // Initialize the member variables. + KeyPoolHeader(); + + // Return true iff the header seems to be correct. + explicit operator bool() const; +}; + +KeyPoolHeader::KeyPoolHeader() + : common_header(FORMAT_STRING), + max_key_id(MAP_MIN_KEY_ID - 1), + num_keys(0), + latest_available_unit_id(INVALID_UNIT_ID), + keys_storage_node_id(STORAGE_INVALID_NODE_ID), + bits_storage_node_id(STORAGE_INVALID_NODE_ID), + links_storage_node_id(STORAGE_INVALID_NODE_ID), + latest_free_entry_id(INVALID_ENTRY_ID), + pool_storage_node_id(STORAGE_INVALID_NODE_ID), + entries_storage_node_id(STORAGE_INVALID_NODE_ID) {} + +KeyPoolHeader::operator bool() const { + return common_header.format() == FORMAT_STRING; +} + +template <typename T> +KeyPool<T>::KeyPool() + : storage_(nullptr), + storage_node_id_(STORAGE_INVALID_NODE_ID), + header_(nullptr), + max_key_id_(nullptr), + num_keys_(nullptr), + keys_(), + bits_(), + links_() {} + +template <typename T> +KeyPool<T>::~KeyPool() {} + +template <typename T> +KeyPool<T> *KeyPool<T>::create(Storage *storage, uint32_t storage_node_id) { + if (!storage) { + GRNXX_ERROR() << "invalid argument: storage == nullptr"; + throw LogicError(); + } + std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool); + if (!pool) { + GRNXX_ERROR() << "new grnxx::map::KeyPool failed"; + throw MemoryError(); + } + pool->create_pool(storage, storage_node_id); + return pool.release(); +} + +template <typename T> +KeyPool<T> *KeyPool<T>::open(Storage *storage, uint32_t storage_node_id) { + if (!storage) { + GRNXX_ERROR() << "invalid argument: storage == nullptr"; + throw LogicError(); + } + std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool); + if (!pool) { + GRNXX_ERROR() << "new grnxx::map::KeyPool failed"; + throw MemoryError(); + } + pool->open_pool(storage, storage_node_id); + return pool.release(); +} + +template <typename T> +void KeyPool<T>::unset(int64_t key_id) { + // Prepare to update "bits_" and "links_". + const uint64_t unit_id = key_id / UNIT_SIZE; + const uint64_t unit_bit = 1ULL << (key_id % UNIT_SIZE); + BitArrayUnit * const unit = &bits_->get_unit(unit_id); + if ((*unit & unit_bit) == 0) { + GRNXX_ERROR() << "not found: key_id = " << key_id; + throw LogicError(); + } + // Set "link" if this operation creates the first 0 bit in the unit. + Link *link = nullptr; + if (*unit == ~BitArrayUnit(0)) { + link = &links_->get_value(unit_id); + } + *unit &= ~unit_bit; + if (link) { + if (header_->latest_available_unit_id != INVALID_UNIT_ID) { + // "*link" points to the next unit. + *link = static_cast<Link>(header_->latest_available_unit_id); + } else { + // "*link" points to itself because there are no more units. + *link = static_cast<Link>(unit_id); + } + header_->latest_available_unit_id = *link; + } + --header_->num_keys; +} + +template <typename T> +void KeyPool<T>::reset(int64_t key_id, KeyArg dest_key) { + if (!get_bit(key_id)) { + GRNXX_ERROR() << "not found: key_id = " << key_id; + throw LogicError(); + } + keys_->set(key_id, dest_key); +} + +template <typename T> +int64_t KeyPool<T>::add(KeyArg key) { + // Find an unused key ID. + const bool is_new_unit = header_->latest_available_unit_id == INVALID_UNIT_ID; + uint64_t unit_id; + if (is_new_unit) { + unit_id = (header_->max_key_id + 1) / UNIT_SIZE; + } else { + unit_id = header_->latest_available_unit_id; + } + BitArrayUnit * const unit = &bits_->get_unit(unit_id); + uint8_t unit_bit_id; + uint64_t unit_bit; + const Link *link = nullptr; + if (is_new_unit) { + // "links_[unit_id]" points to itself because there are no more units. + links_->set(unit_id, unit_id); + *unit = 0; + unit_bit_id = 0; + unit_bit = 1; + header_->latest_available_unit_id = unit_id; + } else { + unit_bit_id = bit_scan_forward(~*unit); + unit_bit = 1ULL << unit_bit_id; + if ((*unit | unit_bit) == ~BitArrayUnit(0)) { + // The unit must be removed from "links_" because it becomes full. + link = &links_->get_value(header_->latest_available_unit_id); + } + } + const int64_t next_key_id = (unit_id * UNIT_SIZE) + unit_bit_id; + keys_->set(next_key_id, key); + if (link) { + if (*link != unit_id) { + // Move to the next unit. + header_->latest_available_unit_id = *link; + } else { + // There are no more units. + header_->latest_available_unit_id = INVALID_UNIT_ID; + } + } + *unit |= unit_bit; + if (next_key_id > header_->max_key_id) { + header_->max_key_id = next_key_id; + } + ++header_->num_keys; + return next_key_id; +} + +template <typename T> +void KeyPool<T>::truncate() { + header_->max_key_id = MAP_MIN_KEY_ID - 1; + header_->num_keys = 0; + header_->latest_available_unit_id = INVALID_UNIT_ID; +} + +template <typename T> +void KeyPool<T>::create_pool(Storage *storage, uint32_t storage_node_id) { + storage_ = storage; + StorageNode storage_node = + storage->create_node(storage_node_id, sizeof(Header)); + storage_node_id_ = storage_node.id(); + try { + header_ = static_cast<Header *>(storage_node.body()); + *header_ = Header(); + max_key_id_ = &header_->max_key_id; + num_keys_ = &header_->num_keys; + keys_.reset(KeyArray::create(storage, storage_node_id_, + KeyPoolHelper<T>::KEY_ARRAY_SIZE)); + bits_.reset(BitArray::create(storage, storage_node_id_, + KeyPoolHelper<T>::BIT_ARRAY_SIZE)); + links_.reset(LinkArray::create(storage, storage_node_id_, + KeyPoolHelper<T>::LINK_ARRAY_SIZE)); + header_->keys_storage_node_id = keys_->storage_node_id(); + header_->bits_storage_node_id = bits_->storage_node_id(); + header_->links_storage_node_id = links_->storage_node_id(); + } catch (...) { + storage->unlink_node(storage_node_id_); + throw; + } +} + +template <typename T> +void KeyPool<T>::open_pool(Storage *storage, uint32_t storage_node_id) { + storage_ = storage; + StorageNode storage_node = storage->open_node(storage_node_id); + storage_node_id_ = storage_node.id(); + header_ = static_cast<Header *>(storage_node.body()); + if (!*header_) { + GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING + << ", actual = " << header_->common_header.format(); + throw LogicError(); + } + max_key_id_ = &header_->max_key_id; + num_keys_ = &header_->num_keys; + keys_.reset(KeyArray::open(storage, header_->keys_storage_node_id)); + bits_.reset(BitArray::open(storage, header_->bits_storage_node_id)); + links_.reset(LinkArray::open(storage, header_->links_storage_node_id)); +} + +template class KeyPool<int8_t>; +template class KeyPool<uint8_t>; +template class KeyPool<int16_t>; +template class KeyPool<uint16_t>; +template class KeyPool<int32_t>; +template class KeyPool<uint32_t>; +template class KeyPool<int64_t>; +template class KeyPool<uint64_t>; +template class KeyPool<double>; +template class KeyPool<GeoPoint>; + +KeyPool<Bytes>::KeyPool() + : storage_(nullptr), + storage_node_id_(STORAGE_INVALID_NODE_ID), + header_(nullptr), + max_key_id_(nullptr), + num_keys_(nullptr), + pool_(), + entries_() {} + +KeyPool<Bytes>::~KeyPool() {} + +KeyPool<Bytes> *KeyPool<Bytes>::create(Storage *storage, + uint32_t storage_node_id) { + if (!storage) { + GRNXX_ERROR() << "invalid argument: storage == nullptr"; + throw LogicError(); + } + std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool); + if (!pool) { + GRNXX_ERROR() << "new grnxx::map::KeyPool failed"; + throw MemoryError(); + } + pool->create_pool(storage, storage_node_id); + return pool.release(); +} + +KeyPool<Bytes> *KeyPool<Bytes>::open(Storage *storage, + uint32_t storage_node_id) { + if (!storage) { + GRNXX_ERROR() << "invalid argument: storage == nullptr"; + throw LogicError(); + } + std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool); + if (!pool) { + GRNXX_ERROR() << "new grnxx::map::KeyPool failed"; + throw MemoryError(); + } + pool->open_pool(storage, storage_node_id); + return pool.release(); +} + +void KeyPool<Bytes>::unset(int64_t key_id) { + Entry &entry = entries_->get_value(key_id); + if (!entry) { + GRNXX_ERROR() << "not found: key_id = " << key_id; + throw LogicError(); + } + pool_->unset(entry.bytes_id()); + entry.set_next_free_entry_id(header_->latest_free_entry_id); + header_->latest_free_entry_id = key_id; + --header_->num_keys; +} + +void KeyPool<Bytes>::reset(int64_t key_id, KeyArg dest_key) { + Entry &entry = entries_->get_value(key_id); + if (!entry) { + GRNXX_ERROR() << "not found: key_id = " << key_id; + throw LogicError(); + } + const uint64_t src_bytes_id = entry.bytes_id(); + entry.set_bytes_id(pool_->add(dest_key)); + pool_->unset(src_bytes_id); +} + +int64_t KeyPool<Bytes>::add(KeyArg key) { + uint64_t entry_id; + if (header_->latest_free_entry_id != INVALID_ENTRY_ID) { + entry_id = header_->latest_free_entry_id; + } else { + entry_id = header_->max_key_id + 1; + } + Entry &entry = entries_->get_value(entry_id); + const uint64_t bytes_id = pool_->add(key); + if (header_->latest_free_entry_id != INVALID_ENTRY_ID) { + header_->latest_free_entry_id = entry.next_free_entry_id(); + } + entry.set_bytes_id(bytes_id); + if (static_cast<int64_t>(entry_id) > header_->max_key_id) { + header_->max_key_id = entry_id; + } + return entry_id; +} + +void KeyPool<Bytes>::truncate() { + header_->max_key_id = MAP_MIN_KEY_ID - 1; + header_->num_keys = 0; + header_->latest_free_entry_id = INVALID_ENTRY_ID; + + // TODO: Truncate pool! +} + +void KeyPool<Bytes>::create_pool(Storage *storage, uint32_t storage_node_id) { + storage_ = storage; + StorageNode storage_node = + storage->create_node(storage_node_id, sizeof(Header)); + storage_node_id_ = storage_node.id(); + try { + header_ = static_cast<Header *>(storage_node.body()); + *header_ = Header(); + max_key_id_ = &header_->max_key_id; + num_keys_ = &header_->num_keys; + pool_.reset(BytesPool::create(storage, storage_node_id_)); + entries_.reset(EntryArray::create(storage, storage_node_id_, + ENTRY_ARRAY_SIZE)); + header_->pool_storage_node_id = pool_->storage_node_id(); + header_->entries_storage_node_id = entries_->storage_node_id(); + } catch (...) { + storage->unlink_node(storage_node_id_); + throw; + } +} + +void KeyPool<Bytes>::open_pool(Storage *storage, uint32_t storage_node_id) { + storage_ = storage; + StorageNode storage_node = storage->open_node(storage_node_id); + storage_node_id_ = storage_node.id(); + header_ = static_cast<Header *>(storage_node.body()); + if (!*header_) { + GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING + << ", actual = " << header_->common_header.format(); + throw LogicError(); + } + max_key_id_ = &header_->max_key_id; + num_keys_ = &header_->num_keys; + pool_.reset(BytesPool::open(storage, header_->pool_storage_node_id)); + entries_.reset(EntryArray::open(storage, header_->entries_storage_node_id)); +} + +} // namespace map +} // namespace grnxx Added: lib/grnxx/map/key_pool.hpp (+301 -0) 100644 =================================================================== --- /dev/null +++ lib/grnxx/map/key_pool.hpp 2013-07-24 12:23:48 +0900 (5b138dc) @@ -0,0 +1,301 @@ +/* + Copyright (C) 2012-2013 Brazil, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef GRNXX_MAP_KEY_POOL_HPP +#define GRNXX_MAP_KEY_POOL_HPP + +#include "grnxx/features.hpp" + +#include <memory> + +#include "grnxx/array.hpp" +#include "grnxx/bytes.hpp" +#include "grnxx/map/bytes_pool.hpp" +#include "grnxx/traits.hpp" +#include "grnxx/types.hpp" + +namespace grnxx { + +class Storage; + +namespace map { + +class BytesPool; + +struct KeyPoolHeader; + +// Change the size of arrays based on "T". +// Note that the size of link array is N/64 where N is the size of KeyArray. +template <typename T, size_t T_SIZE = sizeof(T)> +struct KeyPoolHelper; + +// Map<T> has at most 2^40 different keys. +template <typename T, size_t T_SIZE> +struct KeyPoolHelper { + using KeyArray = Array<T, (1 << 16), (1 << 12)>; + using BitArray = Array<bool, (1 << 18), (1 << 11)>; + using Link = uint64_t; + using LinkArray = Array<Link, (1 << 14), (1 << 10)>; + + static constexpr uint64_t KEY_ARRAY_SIZE = 1ULL << 40; + static constexpr uint64_t BIT_ARRAY_SIZE = 1ULL << 40; + static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 34; +}; + +// Map<T> has at most 2^8 different keys. +template <typename T> +struct KeyPoolHelper<T, 1> { + using KeyArray = Array<T>; + using BitArray = Array<bool>; + using Link = uint8_t; + using LinkArray = Array<Link>; + + static constexpr uint64_t KEY_ARRAY_SIZE = 1ULL << 8; + static constexpr uint64_t BIT_ARRAY_SIZE = 1ULL << 8; + static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 2; +}; + +// Map<T> has at most 2^16 different keys. +template <typename T> +struct KeyPoolHelper<T, 2> { + using KeyArray = Array<T>; + using BitArray = Array<bool>; + using Link = uint16_t; + using LinkArray = Array<Link>; + + static constexpr uint64_t KEY_ARRAY_SIZE = 1ULL << 16; + static constexpr uint64_t BIT_ARRAY_SIZE = 1ULL << 16; + static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 10; +}; + +// Map<T> has at most 2^32 different keys. +template <typename T> +struct KeyPoolHelper<T, 4> { + using KeyArray = Array<T, (1 << 18)>; + using BitArray = Array<bool, (1 << 20)>; + using Link = uint32_t; + using LinkArray = Array<Link, (1 << 15)>; + + static constexpr uint64_t KEY_ARRAY_SIZE = 1ULL << 32; + static constexpr uint64_t BIT_ARRAY_SIZE = 1ULL << 32; + static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 26; +}; + +template <typename T> +class KeyPool { + using Header = KeyPoolHeader; + using KeyArray = typename KeyPoolHelper<T>::KeyArray; + using BitArray = typename KeyPoolHelper<T>::BitArray; + using BitArrayUnit = typename BitArray::Unit; + using Link = typename KeyPoolHelper<T>::Link; + using LinkArray = typename KeyPoolHelper<T>::LinkArray; + + static constexpr uint64_t UNIT_SIZE = sizeof(BitArrayUnit) * 8; + + public: + using Key = typename Traits<T>::Type; + using KeyArg = typename Traits<T>::ArgumentType; + + KeyPool(); + ~KeyPool(); + + // Create a pool. + static KeyPool *create(Storage *storage, uint32_t storage_node_id); + // Open a pool. + static KeyPool *open(Storage *storage, uint32_t storage_node_id); + + // Return the storage node ID. + uint32_t storage_node_id() const { + return storage_node_id_; + } + + // Return the maximum key ID ever used. + // The return value can be a negative value iff the map is empty. + int64_t max_key_id() const { + return *max_key_id_; + } + // Return the number of keys. + uint64_t num_keys() const { + return *num_keys_; + } + + // Get a key associated with "key_id" and return true iff it exists. + // Assign the found key to "*key" iff "key" != nullptr. + bool get(int64_t key_id, Key *key) { + if (!get_bit(key_id)) { + return false; + } + if (key) { + *key = get_key(key_id); + } + return true; + } + // Get a key associated with "key_id" without check. + Key get_key(int64_t key_id) { + return keys_->get(key_id); + } + // Return true iff "key_id" is valid. + bool get_bit(int64_t key_id) { + return bits_->get(key_id); + } + // Remove a key associated with "key_id". + void unset(int64_t key_id); + // Replace a key associated with "key_id" with "dest_key". + void reset(int64_t key_id, KeyArg dest_key); + + // Add "key" and return its ID. + int64_t add(KeyArg key); + + // Remove all the keys. + void truncate(); + + private: + Storage *storage_; + uint32_t storage_node_id_; + Header *header_; + const int64_t *max_key_id_; + const uint64_t *num_keys_; + std::unique_ptr<KeyArray> keys_; + std::unique_ptr<BitArray> bits_; + std::unique_ptr<LinkArray> links_; + + // Create a pool. + void create_pool(Storage *storage, uint32_t storage_node_id); + // Open a pool. + void open_pool(Storage *storage, uint32_t storage_node_id); +}; + +class KeyPoolEntry { + static constexpr uint64_t IS_VALID_FLAG = 1ULL << 63; + + public: + KeyPoolEntry() = default; + + // Return true iff the entry is valid. + explicit operator bool() const { + return value_ & IS_VALID_FLAG; + } + + // Return the ID of the associated byte sequence. + uint64_t bytes_id() const { + return value_ & ~IS_VALID_FLAG; + } + // Return the ID of the next invalid entry. + uint64_t next_free_entry_id() const { + return value_; + } + + // Set the ID of the associated byte sequence. + void set_bytes_id(uint64_t bytes_id) { + value_ = IS_VALID_FLAG | bytes_id; + } + // Set the ID of the next free entry. + void set_next_free_entry_id(uint64_t next_free_entry_id) { + value_ = next_free_entry_id; + } + + private: + uint64_t value_; + + explicit KeyPoolEntry(uint64_t value) : value_(value) {} +}; + +template <> +class KeyPool<Bytes> { + using Header = KeyPoolHeader; + using Entry = KeyPoolEntry; + using EntryArray = Array<Entry, (1 << 16), (1 << 12)>; + + static constexpr uint64_t ENTRY_ARRAY_SIZE = 1ULL << 40; + + public: + using Key = typename Traits<Bytes>::Type; + using KeyArg = typename Traits<Bytes>::ArgumentType; + + KeyPool(); + ~KeyPool(); + + // Create a pool. + static KeyPool *create(Storage *storage, uint32_t storage_node_id); + // Open a pool. + static KeyPool *open(Storage *storage, uint32_t storage_node_id); + + // Return the storage node ID. + uint32_t storage_node_id() const { + return storage_node_id_; + } + + // Return the maximum key ID ever used. + // The return value can be a negative value iff the map is empty. + int64_t max_key_id() const { + return *max_key_id_; + } + // Return the number of keys. + uint64_t num_keys() const { + return *num_keys_; + } + + // Get a key associated with "key_id" and return true iff it exists. + // Assign the found key to "*key" iff "key" != nullptr. + bool get(int64_t key_id, Key *key) { + const Entry entry = entries_->get(key_id); + if (!entry) { + return false; + } + if (key) { + *key = pool_->get(entry.bytes_id()); + } + return true; + } + // Get a key associated with "key_id" without check. + Key get_key(int64_t key_id) { + return pool_->get(entries_->get(key_id).bytes_id()); + } + // Return true iff "key_id" is valid. + bool get_bit(int64_t key_id) { + return bool(entries_->get(key_id)); + } + // Remove a key associated with "key_id". + void unset(int64_t key_id); + // Replace a key associated with "key_id" with "dest_key". + void reset(int64_t key_id, KeyArg dest_key); + + // Add "key" and return its ID. + int64_t add(KeyArg key); + + // Remove all the keys. + void truncate(); + + private: + Storage *storage_; + uint32_t storage_node_id_; + Header *header_; + const int64_t *max_key_id_; + const uint64_t *num_keys_; + std::unique_ptr<BytesPool> pool_; + std::unique_ptr<EntryArray> entries_; + + // Create a pool. + void create_pool(Storage *storage, uint32_t storage_node_id); + // Open a pool. + void open_pool(Storage *storage, uint32_t storage_node_id); +}; + +} // namespace map +} // namespace grnxx + +#endif // GRNXX_MAP_KEY_POOL_HPP -------------- next part -------------- HTML����������������������������... 下载