mem leaks related to exceptions fixed in linear redistribute_elements.

[SVN r81284]
This commit is contained in:
Adam Wulkiewicz
2012-11-10 13:29:07 +00:00
parent 4dc16eb40d
commit d008473125
5 changed files with 109 additions and 65 deletions

View File

@@ -208,7 +208,8 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
Box & box1,
Box & box2,
parameters_type const& parameters,
Translator const& translator)
Translator const& translator,
Allocators & allocators)
{
typedef typename rtree::elements_type<Node>::type elements_type;
typedef typename elements_type::value_type element_type;
@@ -223,7 +224,7 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
BOOST_GEOMETRY_INDEX_ASSERT(elements1.size() == elements1_count, "unexpected number of elements");
// copy original elements
elements_type elements_copy(elements1);
elements_type elements_copy(elements1); // MAY THROW
// calculate initial seeds
size_t seed1 = 0;
@@ -234,78 +235,90 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, linear
elements1.clear();
BOOST_GEOMETRY_INDEX_ASSERT(elements2.empty(), "unexpected container state");
// add seeds
elements1.push_back(elements_copy[seed1]);
elements2.push_back(elements_copy[seed2]);
// calculate boxes
geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
geometry::convert(rtree::element_indexable(elements_copy[seed2], translator), box2);
// initialize areas
content_type content1 = index::content(box1);
content_type content2 = index::content(box2);
BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements1_count, "unexpected elements number");
size_t remaining = elements1_count - 2;
// redistribute the rest of the elements
for ( size_t i = 0 ; i < elements1_count ; ++i )
try
{
if (i != seed1 && i != seed2)
// add seeds
elements1.push_back(elements_copy[seed1]); // MAY THROW
elements2.push_back(elements_copy[seed2]); // MAY THROW
// calculate boxes
geometry::convert(rtree::element_indexable(elements_copy[seed1], translator), box1);
geometry::convert(rtree::element_indexable(elements_copy[seed2], translator), box2);
// initialize areas
content_type content1 = index::content(box1);
content_type content2 = index::content(box2);
BOOST_GEOMETRY_INDEX_ASSERT(2 <= elements1_count, "unexpected elements number");
size_t remaining = elements1_count - 2;
// redistribute the rest of the elements
for ( size_t i = 0 ; i < elements1_count ; ++i )
{
element_type const& elem = elements_copy[i];
indexable_type const& indexable = rtree::element_indexable(elem, translator);
// if there is small number of elements left and the number of elements in node is lesser than min_elems
// just insert them to this node
if ( elements1.size() + remaining <= parameters.get_min_elements() )
if (i != seed1 && i != seed2)
{
elements1.push_back(elem);
geometry::expand(box1, indexable);
content1 = index::content(box1);
}
else if ( elements2.size() + remaining <= parameters.get_min_elements() )
{
elements2.push_back(elem);
geometry::expand(box2, indexable);
content2 = index::content(box2);
}
// choose better node and insert element
else
{
// calculate enlarged boxes and areas
Box enlarged_box1(box1);
Box enlarged_box2(box2);
geometry::expand(enlarged_box1, indexable);
geometry::expand(enlarged_box2, indexable);
content_type enlarged_content1 = index::content(enlarged_box1);
content_type enlarged_content2 = index::content(enlarged_box2);
element_type const& elem = elements_copy[i];
indexable_type const& indexable = rtree::element_indexable(elem, translator);
content_type content_increase1 = enlarged_content1 - content1;
content_type content_increase2 = enlarged_content2 - content2;
// choose group which box content have to be enlarged least or has smaller content or has fewer elements
if ( content_increase1 < content_increase2 ||
( content_increase1 == content_increase2 && content1 < content2 ) ||
( content1 == content2 && elements1.size() <= elements2.size() ) )
// if there is small number of elements left and the number of elements in node is lesser than min_elems
// just insert them to this node
if ( elements1.size() + remaining <= parameters.get_min_elements() )
{
elements1.push_back(elem);
box1 = enlarged_box1;
content1 = enlarged_content1;
elements1.push_back(elem); // MAY THROW
geometry::expand(box1, indexable);
content1 = index::content(box1);
}
else if ( elements2.size() + remaining <= parameters.get_min_elements() )
{
elements2.push_back(elem); // MAY THROW
geometry::expand(box2, indexable);
content2 = index::content(box2);
}
// choose better node and insert element
else
{
elements2.push_back(elem);
box2 = enlarged_box2;
content2 = enlarged_content2;
// calculate enlarged boxes and areas
Box enlarged_box1(box1);
Box enlarged_box2(box2);
geometry::expand(enlarged_box1, indexable);
geometry::expand(enlarged_box2, indexable);
content_type enlarged_content1 = index::content(enlarged_box1);
content_type enlarged_content2 = index::content(enlarged_box2);
content_type content_increase1 = enlarged_content1 - content1;
content_type content_increase2 = enlarged_content2 - content2;
// choose group which box content have to be enlarged least or has smaller content or has fewer elements
if ( content_increase1 < content_increase2 ||
( content_increase1 == content_increase2 && content1 < content2 ) ||
( content1 == content2 && elements1.size() <= elements2.size() ) )
{
elements1.push_back(elem); // MAY THROW
box1 = enlarged_box1;
content1 = enlarged_content1;
}
else
{
elements2.push_back(elem); // MAY THROW
box2 = enlarged_box2;
content2 = enlarged_content2;
}
}
}
assert(0 < remaining);
--remaining;
assert(0 < remaining);
--remaining;
}
}
}
catch (...)
{
elements1.clear();
elements2.clear();
rtree::destroy_elements<Value, Options, Translator, Box, Allocators>::apply(elements_copy, allocators);
throw; // RETHROW
}
}
};

View File

@@ -53,6 +53,29 @@ inline Box elements_box(FwdIter first, FwdIter last, Translator const& tr)
return result;
}
// destroys stored subtrees if internal node's elements are passed
template <typename Value, typename Options, typename Translator, typename Box, typename Allocators>
struct destroy_elements
{
typedef typename Options::parameters_type parameters_type;
typedef typename rtree::internal_node<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type internal_node;
typedef typename rtree::leaf<Value, parameters_type, Box, Allocators, typename Options::node_tag>::type leaf;
typedef rtree::node_auto_ptr<Value, Options, Translator, Box, Allocators> node_auto_ptr;
inline static void apply(typename internal_node::elements_type & elements, Allocators & allocators)
{
for ( size_t i = 0 ; i < elements.size() ; ++i )
{
node_auto_ptr dummy(elements[i].second, allocators);
elements[i].second = 0;
}
}
inline static void apply(typename leaf::elements_type &, Allocators &) {}
};
}} // namespace detail::rtree
}}} // namespace boost::geometry::index

View File

@@ -94,7 +94,8 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, quadra
Box & box1,
Box & box2,
parameters_type const& parameters,
Translator const& translator)
Translator const& translator,
Allocators & allocators)
{
typedef typename rtree::elements_type<Node>::type elements_type;
typedef typename elements_type::value_type element_type;

View File

@@ -334,7 +334,8 @@ struct redistribute_elements<Value, Options, Translator, Box, Allocators, rstar_
Box & box1,
Box & box2,
parameters_type const& parameters,
Translator const& translator)
Translator const& translator,
Allocators & allocators)
{
typedef typename rtree::elements_type<Node>::type elements_type;

View File

@@ -139,6 +139,12 @@ public:
// create reference to the newly created node
Node & n2 = rtree::get<Node>(*second_node);
// After throwing an exception by redistribute_elements both nodes may be empty.
// The tree won't be valid r-tree.
// The alternative is to create 2 (or more) additional nodes here and store backup info
// in the original node, but then, if exception was thrown, the node would have more than max
// elements which also is not allowed in the r-tree.
// redistribute elements
Box box2;
redistribute_elements<
@@ -148,7 +154,7 @@ public:
Box,
Allocators,
typename Options::redistribute_tag
>::apply(n, n2, n_box, box2, parameters, translator); // MAY THROW
>::apply(n, n2, n_box, box2, parameters, translator, allocators); // MAY THROW
// check numbers of elements
BOOST_GEOMETRY_INDEX_ASSERT(parameters.get_min_elements() <= rtree::elements(n).size() &&