Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
c32ee4ee
Commit
c32ee4ee
authored
May 20, 2001
by
monty@donna.mysql.fi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New qsort implementation
parent
ab9c0df7
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
152 additions
and
196 deletions
+152
-196
mysys/mf_qsort.c
mysys/mf_qsort.c
+151
-195
sql/sql_handler.cc
sql/sql_handler.cc
+1
-1
No files found.
mysys/mf_qsort.c
View file @
c32ee4ee
...
@@ -15,245 +15,201 @@
...
@@ -15,245 +15,201 @@
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA */
MA 02111-1307, USA */
/* Plug-compatible replacement for UNIX qsort.
/*
Copyright (C) 1989 Free Software Foundation, Inc.
qsort implementation optimized for comparison of pointers
Written by Douglas C. Schmidt (schmidt@ics.uci.edu)
Inspired by the qsort implementations by Douglas C. Schmidt,
Optimized and modyfied for mysys by monty.
and Bentley & McIlroy's "Engineering a Sort Function".
*/
This file is part of GNU CC.
GNU QSORT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU QSORT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU QSORT; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "mysys_priv.h"
#include "mysys_priv.h"
/*
Envoke the comparison function, returns either 0, < 0, or > 0.
*/
/*
We need to use qsort with 2 different compare functions
*/
#ifdef QSORT_EXTRA_CMP_ARGUMENT
#ifdef QSORT_EXTRA_CMP_ARGUMENT
#define CMP(A,B) ((*cmp)(cmp_argument,(A),(B)))
#define CMP(A,B) ((*cmp)(cmp_argument,(A),(B)))
#else
#else
#define CMP(A,B) ((*cmp)((A),(B)))
#define CMP(A,B) ((*cmp)((A),(B)))
#endif
#endif
/* Byte-wise swap two items of size SIZE. */
#define SWAP(A, B, size,swap_ptrs) \
#define SWAP(A,B,SIZE) do {int sz=(int)(SIZE); char *a = (A); char *b = (B); \
do { \
do { char _temp = *a;*a++ = *b;*b++ = _temp;} while (--sz);} while (0)
if (swap_ptrs) \
{ \
/* Copy SIZE bytes from item B to item A. */
reg1 char **a = (char**) (A), **b = (char**) (B); \
#define COPY(A,B,SIZE) {int sz = (int) (SIZE); do { *(A)++ = *(B)++; } while (--sz); }
char *tmp = *a; *a++ = *b; *b++ = tmp; \
} \
/* This should be replaced by a standard ANSI macro. */
else \
#define BYTES_PER_WORD 8
{ \
reg1 char *a = (A), *b = (B); \
/* The next 4 #defines implement a very fast in-line stack abstraction. */
reg3 char *end= a+size; \
#define STACK_SIZE (BYTES_PER_WORD * sizeof (long))
do \
#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
{ \
#define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
char tmp = *a; *a++ = *b; *b++ = tmp; \
#define STACK_NOT_EMPTY (stack < top)
} while (a < end); \
} \
} while (0)
/* Put the median in the middle argument */
#define MEDIAN(low, mid, high) \
{ \
if (CMP(high,low) < 0) \
SWAP(high, low, size, ptr_cmp); \
if (CMP(mid, low) < 0) \
SWAP(mid, low, size, ptr_cmp); \
else if (CMP(high, mid) < 0) \
SWAP(mid, high, size, ptr_cmp); \
}
/* Discontinue quicksort algorithm when partition gets below this size.
/* The following node is used to store ranges to avoid recursive calls */
This particular magic number was chosen to work best on a Sparc SLC. */
#define MAX_THRESH 12
/* Stack node declarations used to store unfulfilled partition obligations. */
typedef
struct
st_stack
typedef
struct
{
{
char
*
lo
;
char
*
low
,
*
high
;
char
*
hi
;
}
STACK
;
}
stack_node
;
/* Order size using quicksort. This implementation incorporates
#define PUSH(LOW,HIGH) {stack_ptr->low = LOW; stack_ptr++->high = HIGH;}
four optimizations discussed in Sedgewick:
#define POP(LOW,HIGH) {LOW = (--stack_ptr)->low; HIGH = stack_ptr->high;}
1. Non-recursive, using an explicit stack of pointer that store the
next array partition to sort. To save time, this maximum amount
of space required to store an array of MAX_INT is allocated on the
stack. Assuming a 32-bit integer, this needs only 32 *
sizeof (stack_node) == 136 bits. Pretty cheap, actually.
2. Chose the pivot element using a median-of-three decision tree.
This reduces the probability of selecting a bad pivot value and
eliminates certain extraneous comparisons.
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
insertion sort to order the MAX_THRESH items within each partition.
This is a big win, since insertion sort is faster for small, mostly
sorted array segements.
4. The larger of the two sub-partitions is always pushed onto the
stack first, with the algorithm then concentrating on the
smaller partition. This *guarantees* no more than log (n)
stack size is needed (actually O(1) in this case)! */
/* The following stack size is enough for ulong ~0 elements */
#define STACK_SIZE (8 * sizeof(unsigned long int))
#define THRESHOLD_FOR_INSERT_SORT 10
#if defined(QSORT_TYPE_IS_VOID)
#if defined(QSORT_TYPE_IS_VOID)
#define SORT_RETURN return
#define SORT_RETURN return
#else
#else
#define SORT_RETURN return 0
#define SORT_RETURN return 0
#endif
#endif
/****************************************************************************
** 'standard' quicksort with the following extensions:
**
** Can be compiled with the qsort2_cmp compare function
** Store ranges on stack to avoid recursion
** Use insert sort on small ranges
** Optimize for sorting of pointers (used often by MySQL)
** Use median comparison to find partition element
*****************************************************************************/
#ifdef QSORT_EXTRA_CMP_ARGUMENT
#ifdef QSORT_EXTRA_CMP_ARGUMENT
qsort_t
qsort2
(
void
*
base_ptr
,
size_t
total_elems
,
size_t
size
,
qsort2_cmp
cmp
,
qsort_t
qsort2
(
void
*
base_ptr
,
size_t
count
,
size_t
size
,
qsort2_cmp
cmp
,
void
*
cmp_argument
)
void
*
cmp_argument
)
#else
#else
qsort_t
qsort
(
void
*
base_ptr
,
size_t
total_elems
,
size_t
size
,
qsort_cmp
cmp
)
qsort_t
qsort
(
void
*
base_ptr
,
size_t
count
,
size_t
size
,
qsort_cmp
cmp
)
#endif
#endif
{
{
/* Allocating SIZE bytes for a pivot buffer facilitates a better
char
*
low
,
*
high
,
*
pivot
;
algorithm below since we can do comparisons directly on the pivot.
STACK
stack
[
STACK_SIZE
],
*
stack_ptr
;
*/
my_bool
ptr_cmp
;
int
max_thresh
=
(
int
)
(
MAX_THRESH
*
size
);
/* Handle the simple case first */
if
(
total_elems
<=
1
)
/* This will also make the rest of the code simpler */
SORT_RETURN
;
/* Crashes on MSDOS if continues */
if
(
count
<=
1
)
SORT_RETURN
;
if
(
total_elems
>
MAX_THRESH
)
{
low
=
(
char
*
)
base_ptr
;
char
*
lo
=
base_ptr
;
high
=
low
+
size
*
(
count
-
1
);
char
*
hi
=
lo
+
size
*
(
total_elems
-
1
);
stack_ptr
=
stack
+
1
;
stack_node
stack
[
STACK_SIZE
];
/* Largest size needed for 32-bit int!!! */
stack_node
*
top
=
stack
+
1
;
char
*
pivot_buffer
=
(
char
*
)
my_alloca
((
int
)
size
);
#ifdef HAVE_purify
#ifdef HAVE_purify
stack
[
0
].
lo
=
stack
[
0
].
hi
=
0
;
/* The first element in the stack will be accessed for the last POP */
stack
[
0
].
lo
=
stack
[
0
].
hi
=
0
;
#endif
#endif
pivot
=
(
char
*
)
my_alloca
((
int
)
size
);
ptr_cmp
=
size
==
sizeof
(
char
*
)
&&
!
((
low
-
(
char
*
)
0
)
&
(
sizeof
(
char
*
)
-
1
));
/* The following loop sorts elements between high and low */
do
{
char
*
low_ptr
,
*
high_ptr
,
*
mid
;
while
(
STACK_NOT_EMPTY
)
count
=
((
size_t
)
(
high
-
low
)
/
size
)
+
1
;
/* If count is small, then an insert sort is faster than qsort */
if
(
count
<
THRESHOLD_FOR_INSERT_SORT
)
{
{
char
*
left_ptr
;
for
(
low_ptr
=
low
+
size
;
low_ptr
<=
high
;
low_ptr
+=
size
)
char
*
right_ptr
;
{
{
char
*
pivot
=
pivot_buffer
;
char
*
ptr
;
{
for
(
ptr
=
low_ptr
;
ptr
>
low
&&
CMP
(
ptr
-
size
,
ptr
)
>
0
;
/* Select median value from among LO, MID, and HI. Rearrange
ptr
-=
size
)
LO and HI so the three values are sorted. This lowers the
SWAP
(
ptr
,
ptr
-
size
,
size
,
ptr_cmp
);
probability of picking a pathological pivot value and
skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
char
*
mid
=
lo
+
size
*
(((
uint
)
(
hi
-
lo
)
/
(
uint
)
size
)
>>
1
);
if
(
CMP
(
hi
,
lo
)
<
0
)
SWAP
(
hi
,
lo
,
size
);
if
(
CMP
(
mid
,
lo
)
<
0
)
SWAP
(
mid
,
lo
,
size
);
else
if
(
CMP
(
hi
,
mid
)
<
0
)
SWAP
(
mid
,
hi
,
size
);
COPY
(
pivot
,
mid
,
size
);
pivot
=
pivot_buffer
;
}
left_ptr
=
lo
+
size
;
right_ptr
=
hi
-
size
;
/* Here's the famous ``collapse the walls'' section of quicksort.
Gotta like those tight inner loops! They are the main reason
that this algorithm runs much faster than others. */
do
{
while
(
CMP
(
left_ptr
,
pivot
)
<
0
)
left_ptr
+=
size
;
while
(
CMP
(
pivot
,
right_ptr
)
<
0
)
right_ptr
-=
size
;
if
(
left_ptr
<
right_ptr
)
{
SWAP
(
left_ptr
,
right_ptr
,
size
);
left_ptr
+=
size
;
right_ptr
-=
size
;
}
else
if
(
left_ptr
==
right_ptr
)
{
left_ptr
+=
size
;
right_ptr
-=
size
;
break
;
}
}
while
(
left_ptr
<=
right_ptr
);
}
}
POP
(
low
,
high
);
continue
;
}
/* Set up pointers for next iteration. First determine whether
/* Try to find a good middle element */
left and right partitions are below the threshold size. If so,
mid
=
low
+
size
*
(
count
>>
1
);
ignore one or both. Otherwise, push the larger partition's
if
(
count
>
40
)
/* Must be bigger than 24 */
bounds on the stack and continue sorting the smaller one. */
{
size_t
step
=
size
*
(
count
/
8
);
MEDIAN
(
low
,
low
+
step
,
low
+
step
*
2
);
MEDIAN
(
mid
-
step
,
mid
,
mid
+
step
);
MEDIAN
(
high
-
2
*
step
,
high
-
step
,
high
);
/* Put best median in 'mid' */
MEDIAN
(
low
+
step
,
mid
,
high
-
step
);
low_ptr
=
low
;
high_ptr
=
high
;
}
else
{
MEDIAN
(
low
,
mid
,
high
);
/* The low and high argument are already in sorted against 'pivot' */
low_ptr
=
low
+
size
;
high_ptr
=
high
-
size
;
}
memcpy
(
pivot
,
mid
,
size
);
if
((
right_ptr
-
lo
)
<=
max_thresh
)
do
{
{
if
((
hi
-
left_ptr
)
<=
max_thresh
)
/* Ignore both small parts. */
while
(
CMP
(
low_ptr
,
pivot
)
<
0
)
POP
(
lo
,
hi
);
low_ptr
+=
size
;
else
/* Ignore small left part. */
while
(
CMP
(
pivot
,
high_ptr
)
<
0
)
lo
=
left_ptr
;
high_ptr
-=
size
;
}
else
if
((
hi
-
left_ptr
)
<=
max_thresh
)
/* Ignore small right part. */
if
(
low_ptr
<
high_ptr
)
hi
=
right_ptr
;
else
if
((
right_ptr
-
lo
)
>
(
hi
-
left_ptr
))
/* Push larger left part */
{
{
PUSH
(
lo
,
right_ptr
);
SWAP
(
low_ptr
,
high_ptr
,
size
,
ptr_cmp
);
lo
=
left_ptr
;
low_ptr
+=
size
;
high_ptr
-=
size
;
}
}
else
/* Push larger right part */
else
{
{
PUSH
(
left_ptr
,
hi
);
if
(
low_ptr
==
high_ptr
)
hi
=
right_ptr
;
{
low_ptr
+=
size
;
high_ptr
-=
size
;
}
break
;
}
}
}
}
my_afree
(
pivot_buffer
);
while
(
low_ptr
<=
high_ptr
);
}
/* Once the BASE_PTR array is partially sorted by quicksort the rest
is completely sorted using insertion sort, since this is efficient
for partitions below MAX_THRESH size. BASE_PTR points to the beginning
of the array to sort, and END_PTR points at the very last element in
the array (*not* one beyond it!). */
{
char
*
end_ptr
=
(
char
*
)
base_ptr
+
size
*
(
total_elems
-
1
);
char
*
run_ptr
;
char
*
tmp_ptr
=
(
char
*
)
base_ptr
;
char
*
thresh
=
min
(
end_ptr
,
(
char
*
)
base_ptr
+
max_thresh
);
/* Find smallest element in first threshold and place it at the
/*
array's beginning. This is the smallest array element,
Prepare for next iteration.
and the operation speeds up insertion sort's inner loop. */
Skip partitions of size 1 as these doesn't have to be sorted
Push the larger partition and sort the smaller one first.
This ensures that the stack is keept small.
*/
for
(
run_ptr
=
tmp_ptr
+
size
;
run_ptr
<=
thresh
;
run_ptr
+=
size
)
if
((
int
)
(
high_ptr
-
low
)
<=
0
)
if
(
CMP
(
run_ptr
,
tmp_ptr
)
<
0
)
tmp_ptr
=
run_ptr
;
if
(
tmp_ptr
!=
(
char
*
)
base_ptr
)
SWAP
(
tmp_ptr
,
(
char
*
)
base_ptr
,
size
);
/* Insertion sort, running from left-hand-side up to `right-hand-side.'
Pretty much straight out of the original GNU qsort routine. */
for
(
run_ptr
=
(
char
*
)
base_ptr
+
size
;
(
tmp_ptr
=
run_ptr
+=
size
)
<=
end_ptr
;
)
{
{
while
(
CMP
(
run_ptr
,
tmp_ptr
-=
size
)
<
0
)
;
if
((
int
)
(
high
-
low_ptr
)
<=
0
)
if
((
tmp_ptr
+=
size
)
!=
run_ptr
)
{
{
char
*
trav
;
POP
(
low
,
high
);
/* Nothing more to sort */
for
(
trav
=
run_ptr
+
size
;
--
trav
>=
run_ptr
;)
{
char
c
=
*
trav
;
char
*
hi
,
*
lo
;
for
(
hi
=
lo
=
trav
;
(
lo
-=
size
)
>=
tmp_ptr
;
hi
=
lo
)
*
hi
=
*
lo
;
*
hi
=
c
;
}
}
}
else
low
=
low_ptr
;
/* Ignore small left part. */
}
else
if
((
int
)
(
high
-
low_ptr
)
<=
0
)
high
=
high_ptr
;
/* Ignore small right part. */
else
if
((
high_ptr
-
low
)
>
(
high
-
low_ptr
))
{
PUSH
(
low
,
high_ptr
);
/* Push larger left part */
low
=
low_ptr
;
}
else
{
PUSH
(
low_ptr
,
high
);
/* Push larger right part */
high
=
high_ptr
;
}
}
}
}
while
(
stack_ptr
>
stack
);
my_afree
(
pivot
);
SORT_RETURN
;
SORT_RETURN
;
}
}
sql/sql_handler.cc
View file @
c32ee4ee
...
@@ -104,7 +104,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
...
@@ -104,7 +104,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
List_iterator
<
Item
>
it
(
list
);
List_iterator
<
Item
>
it
(
list
);
it
++
;
it
++
;
insert_fields
(
thd
,
tables
,
tables
->
name
,
&
it
);
insert_fields
(
thd
,
tables
,
tables
->
db
,
tables
->
name
,
&
it
);
table
->
file
->
index_init
(
keyno
);
table
->
file
->
index_init
(
keyno
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment