support for >= 256 values per node

pull/5/head
Josh MacDonald 2011-12-14 10:14:35 -08:00
parent dd97f135d0
commit 9fe3bb3b33
4 changed files with 96 additions and 15 deletions

59
btree.h
View File

@ -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);
};
////

View File

@ -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) \

View File

@ -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

View File

@ -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