diff --git a/btree.h b/btree.h index afb508da..d911d5bb 100644 --- a/btree.h +++ b/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 +struct btree_is_node_big : + btree_is_node_big<(TargetNodeSize / 2), (ValueSize / 2)> { +}; +template +struct btree_is_node_big { + enum { + // In the base case, TargetNodeSize corresponds to single-byte + // entries and is the maximum number of values. + is_big = base::integral_constant= 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 +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::is_big, + uint16, + uint8>::type type; +}; + template + 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::type + base_field_type; enum { kTargetNodeSize = TargetNodeSize, @@ -343,7 +377,8 @@ struct btree_common_params { template struct btree_map_params - : public btree_common_params { + : public btree_common_params { typedef Data data_type; typedef Data mapped_type; typedef pair value_type; @@ -368,7 +403,8 @@ struct btree_map_params // A parameters structure for holding the type parameters for a btree_set. template struct btree_set_params - : public btree_common_params { + : public btree_common_params { 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); }; //// diff --git a/btree_bench.cc b/btree_bench.cc index c67dd664..94a1f272 100644 --- a/btree_bench.cc +++ b/btree_bench.cc @@ -401,7 +401,10 @@ typedef multimap 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) \ diff --git a/btree_nc.cc b/btree_nc.cc index 7f1260be..0a6ef512 100644 --- a/btree_nc.cc +++ b/btree_nc.cc @@ -43,7 +43,10 @@ TEST_COMPARE_TO(float); TEST_COMPARE_TO(void*); #elif defined(TEST_large_nodesize) void LargeNode() { - util::btree::btree_set, std::allocator, 10000> set; + // (1 << 20) with 8-byte values is 2^17 values per node, which + // overflows the uint16 of btree::node_type::base_fields. + util::btree::btree_set, std::allocator, 1 << 20> + large_node_set; } #endif diff --git a/btree_test.cc b/btree_test.cc index ef4e574e..d984ec64 100644 --- a/btree_test.cc +++ b/btree_test.cc @@ -47,6 +47,25 @@ TEST(Btree, map_string_256) { MapTest(); } TEST(Btree, map_cord_256) { MapTest(); } TEST(Btree, map_pair_256) { MapTest, 256>(); } +// Large-node tests +TEST(Btree, map_int32_1024) { MapTest(); } +TEST(Btree, map_int32_1032) { MapTest(); } +TEST(Btree, map_int32_1040) { MapTest(); } +TEST(Btree, map_int32_1048) { MapTest(); } +TEST(Btree, map_int32_1056) { MapTest(); } + +TEST(Btree, map_int32_2048) { MapTest(); } +TEST(Btree, map_int32_4096) { MapTest(); } +TEST(Btree, set_int32_1024) { SetTest(); } +TEST(Btree, set_int32_2048) { SetTest(); } +TEST(Btree, set_int32_4096) { SetTest(); } +TEST(Btree, map_string_1024) { MapTest(); } +TEST(Btree, map_string_2048) { MapTest(); } +TEST(Btree, map_string_4096) { MapTest(); } +TEST(Btree, set_string_1024) { SetTest(); } +TEST(Btree, set_string_2048) { SetTest(); } +TEST(Btree, set_string_4096) { SetTest(); } + template void MultiSetTest() { typedef ArenaAllocator ArenaAlloc; @@ -77,6 +96,20 @@ TEST(Btree, multimap_string_256) { MultiMapTest(); } TEST(Btree, multimap_cord_256) { MultiMapTest(); } TEST(Btree, multimap_pair_256) { MultiMapTest, 256>(); } +// Large-node tests +TEST(Btree, multimap_int32_1024) { MultiMapTest(); } +TEST(Btree, multimap_int32_2048) { MultiMapTest(); } +TEST(Btree, multimap_int32_4096) { MultiMapTest(); } +TEST(Btree, multiset_int32_1024) { MultiSetTest(); } +TEST(Btree, multiset_int32_2048) { MultiSetTest(); } +TEST(Btree, multiset_int32_4096) { MultiSetTest(); } +TEST(Btree, multimap_string_1024) { MultiMapTest(); } +TEST(Btree, multimap_string_2048) { MultiMapTest(); } +TEST(Btree, multimap_string_4096) { MultiMapTest(); } +TEST(Btree, multiset_string_1024) { MultiSetTest(); } +TEST(Btree, multiset_string_2048) { MultiSetTest(); } +TEST(Btree, multiset_string_4096) { MultiSetTest(); } + // 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