Skip to content

Commit c7c20e3

Browse files
author
Tor Didriksen
committed
Bug#20075406 TEMPLATE-BASED QUEUE/HEAP IN BOUNDED_QUEUE
Our QUEUE implementation should be replaced by a templatized C++ version. Templatized heaps are - type safe - easier to read/maintain - faster Some changed results for queries doing 'ORDER BY CHAR(0) NOT NULL limit N'
1 parent 60defae commit c7c20e3

18 files changed

+761
-210
lines changed

include/priority_queue.h

+18-14
Original file line numberDiff line numberDiff line change
@@ -116,25 +116,29 @@ class Priority_queue : public Less
116116
void heapify(size_type i, size_type last)
117117
{
118118
DBUG_ASSERT(i < size());
119-
size_type l = left(i);
120-
size_type r = right(i);
121119
size_type largest = i;
122120

123-
if (l < last && Base::operator()(m_container[i], m_container[l]))
121+
do
124122
{
125-
largest = l;
126-
}
123+
i = largest;
124+
size_type l = left(i);
125+
size_type r = right(i);
127126

128-
if (r < last && Base::operator()(m_container[largest], m_container[r]))
129-
{
130-
largest = r;
131-
}
127+
if (l < last && Base::operator()(m_container[i], m_container[l]))
128+
{
129+
largest = l;
130+
}
132131

133-
if (largest != i)
134-
{
135-
std::swap(m_container[i], m_container[largest]);
136-
heapify(largest, last);
137-
}
132+
if (r < last && Base::operator()(m_container[largest], m_container[r]))
133+
{
134+
largest = r;
135+
}
136+
137+
if (largest != i)
138+
{
139+
std::swap(m_container[i], m_container[largest]);
140+
}
141+
} while (largest != i);
138142
}
139143

140144
void heapify(size_type i)

mysql-test/r/select_all.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4791,7 +4791,7 @@ Warnings:
47914791
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47924792
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47934793
a b c
4794-
1
4794+
0
47954795
2
47964796
1
47974797
0

mysql-test/r/select_all_bka.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4792,7 +4792,7 @@ Warnings:
47924792
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47934793
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47944794
a b c
4795-
1
4795+
0
47964796
2
47974797
1
47984798
0

mysql-test/r/select_all_bka_nixbnl.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4792,7 +4792,7 @@ Warnings:
47924792
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47934793
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47944794
a b c
4795-
1
4795+
0
47964796
2
47974797
1
47984798
0

mysql-test/r/select_icp_mrr.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4791,7 +4791,7 @@ Warnings:
47914791
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47924792
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47934793
a b c
4794-
1
4794+
0
47954795
2
47964796
1
47974797
0

mysql-test/r/select_icp_mrr_bka.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4792,7 +4792,7 @@ Warnings:
47924792
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47934793
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47944794
a b c
4795-
1
4795+
0
47964796
2
47974797
1
47984798
0

mysql-test/r/select_icp_mrr_bka_nixbnl.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4792,7 +4792,7 @@ Warnings:
47924792
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47934793
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47944794
a b c
4795-
1
4795+
0
47964796
2
47974797
1
47984798
0

mysql-test/r/select_none.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4790,7 +4790,7 @@ Warnings:
47904790
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47914791
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47924792
a b c
4793-
1
4793+
0
47944794
2
47954795
1
47964796
0

mysql-test/r/select_none_bka.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4791,7 +4791,7 @@ Warnings:
47914791
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47924792
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47934793
a b c
4794-
1
4794+
0
47954795
2
47964796
1
47974797
0

mysql-test/r/select_none_bka_nixbnl.result

+1-1
Original file line numberDiff line numberDiff line change
@@ -4791,7 +4791,7 @@ Warnings:
47914791
Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` order by `test`.`t1`.`a`,`test`.`t1`.`b` limit 5
47924792
SELECT * FROM t1 ORDER BY a, b LIMIT 5;
47934793
a b c
4794-
1
4794+
0
47954795
2
47964796
1
47974797
0

sql/bounded_queue.h

+47-119
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -16,80 +16,70 @@
1616
#ifndef BOUNDED_QUEUE_INCLUDED
1717
#define BOUNDED_QUEUE_INCLUDED
1818

19-
#include <string.h>
2019
#include "my_global.h"
2120
#include "my_base.h"
2221
#include "my_sys.h"
23-
#include "queues.h"
22+
#include "mysys_err.h"
23+
#include "priority_queue.h"
2424

2525
/**
2626
A priority queue with a fixed, limited size.
2727
28-
This is a wrapper on top of QUEUE and the queue_xxx() functions.
28+
This is a wrapper on top of Priority_queue.
2929
It keeps the top-N elements which are inserted.
3030
3131
Elements of type Element_type are pushed into the queue.
3232
For each element, we call a user-supplied Key_generator::make_sortkey(),
3333
to generate a key of type Key_type for the element.
34-
Instances of Key_type are compared with the user-supplied compare_function.
35-
36-
The underlying QUEUE implementation needs one extra element for replacing
37-
the lowest/highest element when pushing into a full queue.
34+
Instances of Key_type are compared with the user-supplied Key_compare.
3835
3936
Pointers to the top-N elements are stored in the sort_keys array given
40-
to the init() function below. To access elements in sorted order, use
41-
repeated calls to pop(), or, simply sort the array and access it sequentially.
42-
The pop() interface is for unit testing only.
37+
to the init() function below. To access elements in sorted order,
38+
sort the array and access it sequentially.
4339
*/
44-
template<typename Element_type, typename Key_type, typename Key_generator>
40+
template<typename Element_type,
41+
typename Key_type,
42+
typename Key_generator,
43+
typename Key_compare = std::less<Key_type>
44+
>
4545
class Bounded_queue
4646
{
4747
public:
4848
Bounded_queue()
49-
{
50-
memset(&m_queue, 0, sizeof(m_queue));
51-
}
52-
53-
~Bounded_queue()
54-
{
55-
delete_queue(&m_queue);
56-
}
57-
58-
/**
59-
Function for comparing two keys.
60-
@param n Pointer to number of bytes to compare.
61-
@param a First key.
62-
@param b Second key.
63-
@retval -1, 0, or 1 depending on whether the left argument is
64-
less than, equal to, or greater than the right argument.
65-
*/
66-
typedef int (*compare_function)(size_t *n, Key_type *a, Key_type *b);
49+
: m_sort_keys(NULL),
50+
m_sort_param(NULL)
51+
{}
6752

6853
/**
6954
Initialize the queue.
7055
7156
@param max_elements The size of the queue.
72-
@param max_at_top Set to true if you want biggest element on top.
73-
false: We keep the n largest elements.
74-
pop() will return the smallest key in the result set.
75-
true: We keep the n smallest elements.
76-
pop() will return the largest key in the result set.
77-
@param compare Compare function for elements, takes 3 arguments.
78-
If NULL, we use get_ptr_compare(sort_param->compare_length()).
7957
@param sort_param Sort parameters. We call sort_param->make_sortkey()
8058
to generate keys for elements.
8159
@param[in,out] sort_keys Array of keys to sort.
8260
Must be initialized by caller.
8361
Will be filled with pointers to the top-N elements.
8462
85-
@retval 0 OK, 1 Could not allocate memory.
63+
@retval false OK, true Could not allocate memory.
8664
8765
We do *not* take ownership of any of the input pointer arguments.
8866
*/
89-
int init(ha_rows max_elements, bool max_at_top,
90-
compare_function compare,
91-
Key_generator *sort_param,
92-
Key_type *sort_keys);
67+
bool init(ha_rows max_elements,
68+
Key_generator *sort_param,
69+
Key_type *sort_keys)
70+
{
71+
m_sort_keys= sort_keys;
72+
m_sort_param= sort_param;
73+
DBUG_EXECUTE_IF("bounded_queue_init_fail",
74+
my_error(EE_OUTOFMEMORY, MYF(ME_FATALERROR), 42);
75+
return true;);
76+
77+
// We allocate space for one extra element, for replace when queue is full.
78+
if (m_queue.reserve(max_elements + 1))
79+
return true;
80+
m_queue.m_compare_length= sort_param->compare_length();
81+
return false;
82+
}
9383

9484
/**
9585
Pushes an element on the queue.
@@ -98,94 +88,32 @@ class Bounded_queue
9888
9989
@param element The element to be pushed.
10090
*/
101-
void push(Element_type element);
102-
103-
/**
104-
Removes the top element from the queue.
105-
106-
@retval Pointer to the (key of the) removed element.
107-
108-
@note This function is for unit testing, where we push elements into to the
109-
queue, and test that the appropriate keys are retained.
110-
Interleaving of push() and pop() operations has not been tested.
111-
*/
112-
Key_type *pop()
91+
void push(Element_type element)
11392
{
114-
// Don't return the extra element to the client code.
115-
if (queue_is_full((&m_queue)))
116-
queue_remove(&m_queue, 0);
117-
DBUG_ASSERT(m_queue.elements > 0);
118-
if (m_queue.elements == 0)
119-
return NULL;
120-
return reinterpret_cast<Key_type*>(queue_remove(&m_queue, 0));
93+
if (m_queue.size() == m_queue.capacity())
94+
{
95+
const Key_type &pq_top= m_queue.top();
96+
m_sort_param->make_sortkey(pq_top, element);
97+
m_queue.update_top();
98+
} else {
99+
m_sort_param->make_sortkey(m_sort_keys[m_queue.size()], element);
100+
m_queue.push(m_sort_keys[m_queue.size()]);
101+
}
121102
}
122103

123104
/**
124105
The number of elements in the queue.
125106
*/
126-
uint num_elements() const { return m_queue.elements; }
107+
size_t num_elements() const { return m_queue.size(); }
127108

128-
/**
129-
Is the queue initialized?
130-
*/
131-
bool is_initialized() const { return m_queue.max_elements > 0; }
109+
typedef Priority_queue<Key_type,
110+
std::vector<Key_type>,
111+
Key_compare> Queue_type;
132112

133113
private:
114+
Queue_type m_queue;
134115
Key_type *m_sort_keys;
135-
size_t m_compare_length;
136116
Key_generator *m_sort_param;
137-
st_queue m_queue;
138117
};
139118

140-
141-
template<typename Element_type, typename Key_type, typename Key_generator>
142-
int Bounded_queue<Element_type, Key_type, Key_generator>
143-
::init(ha_rows max_elements,
144-
bool max_at_top,
145-
compare_function compare,
146-
Key_generator *sort_param,
147-
Key_type *sort_keys)
148-
{
149-
DBUG_ASSERT(sort_keys != NULL);
150-
151-
m_sort_keys= sort_keys;
152-
m_compare_length= sort_param->compare_length();
153-
m_sort_param= sort_param;
154-
// init_queue() takes an uint, and also does (max_elements + 1)
155-
if (max_elements >= (UINT_MAX - 1))
156-
return 1;
157-
if (compare == NULL)
158-
compare=
159-
reinterpret_cast<compare_function>(get_ptr_compare(m_compare_length));
160-
161-
DBUG_EXECUTE_IF("bounded_queue_init_fail",
162-
DBUG_SET("+d,simulate_out_of_memory"););
163-
164-
// We allocate space for one extra element, for replace when queue is full.
165-
return init_queue(&m_queue, (uint) max_elements + 1,
166-
0, max_at_top,
167-
reinterpret_cast<queue_compare>(compare),
168-
&m_compare_length);
169-
}
170-
171-
172-
template<typename Element_type, typename Key_type, typename Key_generator>
173-
void Bounded_queue<Element_type, Key_type, Key_generator>
174-
::push(Element_type element)
175-
{
176-
DBUG_ASSERT(is_initialized());
177-
if (queue_is_full((&m_queue)))
178-
{
179-
// Replace top element with new key, and re-order the queue.
180-
Key_type *pq_top= reinterpret_cast<Key_type *>(queue_top(&m_queue));
181-
m_sort_param->make_sortkey(*pq_top, element);
182-
queue_replaced(&m_queue);
183-
} else {
184-
// Insert new key into the queue.
185-
m_sort_param->make_sortkey(m_sort_keys[m_queue.elements], element);
186-
queue_insert(&m_queue,
187-
reinterpret_cast<uchar*>(&m_sort_keys[m_queue.elements]));
188-
}
189-
}
190-
191119
#endif // BOUNDED_QUEUE_INCLUDED

0 commit comments

Comments
 (0)