support for >= 256 values per node
parent
dd97f135d0
commit
9fe3bb3b33
59
btree.h
59
btree.h
|
@ -316,8 +316,40 @@ static bool btree_compare_keys(
|
|||
return key_comparer::bool_compare(comp, x, y);
|
||||
}
|
||||
|
||||
// btree_is_node_big<> is a recursive template to determine whether a
|
||||
// node of TargetNodeSize bytes needs a larger base_fields type
|
||||
// (uint16, instead of uint8) to accomodate >= 256 values per node.
|
||||
template <int TargetNodeSize, int ValueSize>
|
||||
struct btree_is_node_big :
|
||||
btree_is_node_big<(TargetNodeSize / 2), (ValueSize / 2)> {
|
||||
};
|
||||
template <int TargetNodeSize>
|
||||
struct btree_is_node_big<TargetNodeSize, 1> {
|
||||
enum {
|
||||
// In the base case, TargetNodeSize corresponds to single-byte
|
||||
// entries and is the maximum number of values.
|
||||
is_big = base::integral_constant<bool, (TargetNodeSize >= 256)>::value,
|
||||
};
|
||||
};
|
||||
|
||||
// A helper for sizing the btree node's base_fields. The "type"
|
||||
// typedef in this struct is an integral type large enough to hold as
|
||||
// many ValueSize-values as will fit a node of TargetNodeSize bytes.
|
||||
template <int TargetNodeSize, int ValueSize>
|
||||
struct btree_base_field_type {
|
||||
enum {
|
||||
// "value_space" is the maximum leaf node count. leaf nodes have
|
||||
// a greatest maximum of the node types.
|
||||
value_space = TargetNodeSize - 2 * sizeof(void*),
|
||||
};
|
||||
typedef typename base::if_<
|
||||
btree_is_node_big<value_space, ValueSize>::is_big,
|
||||
uint16,
|
||||
uint8>::type type;
|
||||
};
|
||||
|
||||
template <typename Key, typename Compare,
|
||||
typename Alloc, int TargetNodeSize>
|
||||
typename Alloc, int TargetNodeSize, int ValueSize>
|
||||
struct btree_common_params {
|
||||
// If Compare is derived from btree_key_compare_to_tag then use it as the
|
||||
// key_compare type. Otherwise, use btree_key_compare_to_adapter<> which will
|
||||
|
@ -333,6 +365,8 @@ struct btree_common_params {
|
|||
typedef Key key_type;
|
||||
typedef ssize_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef typename btree_base_field_type<TargetNodeSize, ValueSize>::type
|
||||
base_field_type;
|
||||
|
||||
enum {
|
||||
kTargetNodeSize = TargetNodeSize,
|
||||
|
@ -343,7 +377,8 @@ struct btree_common_params {
|
|||
template <typename Key, typename Data, typename Compare,
|
||||
typename Alloc, int TargetNodeSize>
|
||||
struct btree_map_params
|
||||
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize> {
|
||||
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize,
|
||||
sizeof(Key) + sizeof(Data)> {
|
||||
typedef Data data_type;
|
||||
typedef Data mapped_type;
|
||||
typedef pair<const Key, data_type> value_type;
|
||||
|
@ -368,7 +403,8 @@ struct btree_map_params
|
|||
// A parameters structure for holding the type parameters for a btree_set.
|
||||
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize>
|
||||
struct btree_set_params
|
||||
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize> {
|
||||
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize,
|
||||
sizeof(Key)> {
|
||||
typedef base::false_type data_type;
|
||||
typedef base::false_type mapped_type;
|
||||
typedef Key value_type;
|
||||
|
@ -505,14 +541,16 @@ class btree_node {
|
|||
linear_search_type, binary_search_type>::type search_type;
|
||||
|
||||
struct base_fields {
|
||||
typedef typename Params::base_field_type field_type;
|
||||
|
||||
// A boolean indicating whether the node is a leaf or not.
|
||||
uint8 leaf;
|
||||
bool leaf;
|
||||
// The position of the node in the node's parent.
|
||||
uint8 position;
|
||||
field_type position;
|
||||
// The maximum number of values the node can hold.
|
||||
uint8 max_count;
|
||||
field_type max_count;
|
||||
// The count of the number of values in the node.
|
||||
uint8 count;
|
||||
field_type count;
|
||||
// A pointer to the node's parent.
|
||||
btree_node *parent;
|
||||
};
|
||||
|
@ -1437,9 +1475,10 @@ class btree : public Params::key_compare {
|
|||
key_comparison_function_must_return_bool);
|
||||
|
||||
// Note: We insist on kTargetValues, which is computed from
|
||||
// Params::kTargetNodeSize, falling under 256 because of the uint8
|
||||
// fields of base_fields.
|
||||
COMPILE_ASSERT(kNodeValues < 256, target_node_size_too_large);
|
||||
// Params::kTargetNodeSize, must fit the base_fields::field_type.
|
||||
COMPILE_ASSERT(kNodeValues <
|
||||
(1 << (8 * sizeof(typename base_fields::field_type))),
|
||||
target_node_size_too_large);
|
||||
};
|
||||
|
||||
////
|
||||
|
|
|
@ -401,7 +401,10 @@ typedef multimap<Cord, intptr_t> stl_multimap_cord;
|
|||
MY_BENCHMARK_TYPES2(value, name, 416); \
|
||||
MY_BENCHMARK_TYPES2(value, name, 448); \
|
||||
MY_BENCHMARK_TYPES2(value, name, 480); \
|
||||
MY_BENCHMARK_TYPES2(value, name, 512)
|
||||
MY_BENCHMARK_TYPES2(value, name, 512); \
|
||||
MY_BENCHMARK_TYPES2(value, name, 1024); \
|
||||
MY_BENCHMARK_TYPES2(value, name, 1536); \
|
||||
MY_BENCHMARK_TYPES2(value, name, 2048)
|
||||
|
||||
MY_BENCHMARK_TYPES(int32, int32);
|
||||
MY_BENCHMARK_TYPES(int64, int64);
|
||||
|
@ -433,10 +436,14 @@ MY_BENCHMARK_TYPES(Cord, cord);
|
|||
MY_BENCHMARK4(tree ## _416_ ## type, name, func); \
|
||||
MY_BENCHMARK4(tree ## _448_ ## type, name, func); \
|
||||
MY_BENCHMARK4(tree ## _480_ ## type, name, func); \
|
||||
MY_BENCHMARK4(tree ## _512_ ## type, name, func)
|
||||
MY_BENCHMARK4(tree ## _512_ ## type, name, func); \
|
||||
MY_BENCHMARK4(tree ## _1024_ ## type, name, func); \
|
||||
MY_BENCHMARK4(tree ## _1536_ ## type, name, func); \
|
||||
MY_BENCHMARK4(tree ## _2048_ ## type, name, func)
|
||||
#else
|
||||
#define MY_BENCHMARK3(tree, type, name, func) \
|
||||
MY_BENCHMARK4(tree ## _256_ ## type, name, func)
|
||||
MY_BENCHMARK4(tree ## _256_ ## type, name, func); \
|
||||
MY_BENCHMARK4(tree ## _2048_ ## type, name, func)
|
||||
#endif
|
||||
|
||||
#define MY_BENCHMARK2(type, name, func) \
|
||||
|
|
|
@ -43,7 +43,10 @@ TEST_COMPARE_TO(float);
|
|||
TEST_COMPARE_TO(void*);
|
||||
#elif defined(TEST_large_nodesize)
|
||||
void LargeNode() {
|
||||
util::btree::btree_set<int64, less<int64>, std::allocator<int64>, 10000> set;
|
||||
// (1 << 20) with 8-byte values is 2^17 values per node, which
|
||||
// overflows the uint16 of btree<Params>::node_type::base_fields.
|
||||
util::btree::btree_set<int64, less<int64>, std::allocator<int64>, 1 << 20>
|
||||
large_node_set;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -47,6 +47,25 @@ TEST(Btree, map_string_256) { MapTest<string, 256>(); }
|
|||
TEST(Btree, map_cord_256) { MapTest<Cord, 256>(); }
|
||||
TEST(Btree, map_pair_256) { MapTest<pair<int, int>, 256>(); }
|
||||
|
||||
// Large-node tests
|
||||
TEST(Btree, map_int32_1024) { MapTest<int32, 1024>(); }
|
||||
TEST(Btree, map_int32_1032) { MapTest<int32, 1032>(); }
|
||||
TEST(Btree, map_int32_1040) { MapTest<int32, 1040>(); }
|
||||
TEST(Btree, map_int32_1048) { MapTest<int32, 1048>(); }
|
||||
TEST(Btree, map_int32_1056) { MapTest<int32, 1056>(); }
|
||||
|
||||
TEST(Btree, map_int32_2048) { MapTest<int32, 2048>(); }
|
||||
TEST(Btree, map_int32_4096) { MapTest<int32, 4096>(); }
|
||||
TEST(Btree, set_int32_1024) { SetTest<int32, 1024>(); }
|
||||
TEST(Btree, set_int32_2048) { SetTest<int32, 2048>(); }
|
||||
TEST(Btree, set_int32_4096) { SetTest<int32, 4096>(); }
|
||||
TEST(Btree, map_string_1024) { MapTest<string, 1024>(); }
|
||||
TEST(Btree, map_string_2048) { MapTest<string, 2048>(); }
|
||||
TEST(Btree, map_string_4096) { MapTest<string, 4096>(); }
|
||||
TEST(Btree, set_string_1024) { SetTest<string, 1024>(); }
|
||||
TEST(Btree, set_string_2048) { SetTest<string, 2048>(); }
|
||||
TEST(Btree, set_string_4096) { SetTest<string, 4096>(); }
|
||||
|
||||
template <typename K, int N>
|
||||
void MultiSetTest() {
|
||||
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
|
||||
|
@ -77,6 +96,20 @@ TEST(Btree, multimap_string_256) { MultiMapTest<string, 256>(); }
|
|||
TEST(Btree, multimap_cord_256) { MultiMapTest<Cord, 256>(); }
|
||||
TEST(Btree, multimap_pair_256) { MultiMapTest<pair<int, int>, 256>(); }
|
||||
|
||||
// Large-node tests
|
||||
TEST(Btree, multimap_int32_1024) { MultiMapTest<int32, 1024>(); }
|
||||
TEST(Btree, multimap_int32_2048) { MultiMapTest<int32, 2048>(); }
|
||||
TEST(Btree, multimap_int32_4096) { MultiMapTest<int32, 4096>(); }
|
||||
TEST(Btree, multiset_int32_1024) { MultiSetTest<int32, 1024>(); }
|
||||
TEST(Btree, multiset_int32_2048) { MultiSetTest<int32, 2048>(); }
|
||||
TEST(Btree, multiset_int32_4096) { MultiSetTest<int32, 4096>(); }
|
||||
TEST(Btree, multimap_string_1024) { MultiMapTest<string, 1024>(); }
|
||||
TEST(Btree, multimap_string_2048) { MultiMapTest<string, 2048>(); }
|
||||
TEST(Btree, multimap_string_4096) { MultiMapTest<string, 4096>(); }
|
||||
TEST(Btree, multiset_string_1024) { MultiSetTest<string, 1024>(); }
|
||||
TEST(Btree, multiset_string_2048) { MultiSetTest<string, 2048>(); }
|
||||
TEST(Btree, multiset_string_4096) { MultiSetTest<string, 4096>(); }
|
||||
|
||||
// Verify that swapping btrees swaps the key comparision functors.
|
||||
struct SubstringLess {
|
||||
SubstringLess() : n(2) {}
|
||||
|
@ -155,7 +188,6 @@ TEST(Btree, IteratorIncrementBy) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace btree
|
||||
} // namespace util
|
||||
|
|
Loading…
Reference in New Issue