sort.cpp (Firebird-3.0.2.32703-0.tar.bz2) | : | sort.cpp (Firebird-3.0.4.33054-0.tar.bz2) | ||
---|---|---|---|---|
skipping to change at line 387 | skipping to change at line 387 | |||
diddleKey((UCHAR*) (record->sr_sort_record.sort_record_ke y), true); | diddleKey((UCHAR*) (record->sr_sort_record.sort_record_ke y), true); | |||
} | } | |||
// If there isn't room for the record, sort and write the run. | // If there isn't room for the record, sort and write the run. | |||
// Check that we are not at the beginning of the buffer in additi on | // Check that we are not at the beginning of the buffer in additi on | |||
// to checking for space for the record. This avoids the pointer | // to checking for space for the record. This avoids the pointer | |||
// record from underflowing in the second condition. | // record from underflowing in the second condition. | |||
if ((UCHAR*) record < m_memory + m_longs || | if ((UCHAR*) record < m_memory + m_longs || | |||
(UCHAR*) NEXT_RECORD(record) <= (UCHAR*) (m_next_pointer + 1)) | (UCHAR*) NEXT_RECORD(record) <= (UCHAR*) (m_next_pointer + 1)) | |||
{ | { | |||
putRun(); | putRun(tdbb); | |||
while (true) | while (true) | |||
{ | { | |||
run_control* run = m_runs; | run_control* run = m_runs; | |||
const USHORT depth = run->run_depth; | const USHORT depth = run->run_depth; | |||
if (depth == MAX_MERGE_LEVEL) | if (depth == MAX_MERGE_LEVEL) | |||
break; | break; | |||
USHORT count = 1; | USHORT count = 1; | |||
while ((run = run->run_next) && run->run_depth == depth) | while ((run = run->run_next) && run->run_depth == depth) | |||
count++; | count++; | |||
if (count < RUN_GROUP) | if (count < RUN_GROUP) | |||
skipping to change at line 454 | skipping to change at line 454 | |||
{ | { | |||
if (m_last_record != (SR*) m_end_memory) | if (m_last_record != (SR*) m_end_memory) | |||
{ | { | |||
diddleKey((UCHAR*) KEYOF(m_last_record), true); | diddleKey((UCHAR*) KEYOF(m_last_record), true); | |||
} | } | |||
// If there aren't any runs, things fit nicely in memory. Just so rt the mess | // If there aren't any runs, things fit nicely in memory. Just so rt the mess | |||
// and we're ready for output. | // and we're ready for output. | |||
if (!m_runs) | if (!m_runs) | |||
{ | { | |||
sort(); | sortBuffer(tdbb); | |||
m_next_pointer = m_first_pointer + 1; | m_next_pointer = m_first_pointer + 1; | |||
m_flags |= scb_sorted; | m_flags |= scb_sorted; | |||
return; | return; | |||
} | } | |||
// Write the last records as a run_control | // Write the last records as a run_control | |||
putRun(); | putRun(tdbb); | |||
CHECK_FILE(NULL); | CHECK_FILE(NULL); | |||
// Merge runs of low depth to free memory part of temp space | // Merge runs of low depth to free memory part of temp space | |||
// they use and to make total runs count lower. This is fast | // they use and to make total runs count lower. This is fast | |||
// because low depth runs usually sit in memory | // because low depth runs usually sit in memory | |||
ULONG run_count = 0, low_depth_cnt = 0; | ULONG run_count = 0, low_depth_cnt = 0; | |||
for (run = m_runs; run; run = run->run_next) | for (run = m_runs; run; run = run->run_next) | |||
{ | { | |||
++run_count; | ++run_count; | |||
skipping to change at line 497 | skipping to change at line 497 | |||
for (run_count = 0, run = m_runs; run; run = run->run_next) | for (run_count = 0, run = m_runs; run; run = run->run_next) | |||
{ | { | |||
if (run->run_buff_alloc) | if (run->run_buff_alloc) | |||
{ | { | |||
delete[] run->run_buffer; | delete[] run->run_buffer; | |||
run->run_buff_alloc = false; | run->run_buff_alloc = false; | |||
} | } | |||
++run_count; | ++run_count; | |||
} | } | |||
AutoPtr<run_merge_hdr*, ArrayDelete<run_merge_hdr*> > streams( | AutoPtr<run_merge_hdr*, ArrayDelete> streams( | |||
FB_NEW_POOL(m_owner->getPool()) run_merge_hdr*[run_count] ); | FB_NEW_POOL(m_owner->getPool()) run_merge_hdr*[run_count] ); | |||
run_merge_hdr** m1 = streams; | run_merge_hdr** m1 = streams; | |||
for (run = m_runs; run; run = run->run_next) | for (run = m_runs; run; run = run->run_next) | |||
*m1++ = (run_merge_hdr*) run; | *m1++ = (run_merge_hdr*) run; | |||
ULONG count = run_count; | ULONG count = run_count; | |||
// We're building a b-tree of the sort merge blocks, we have (cou nt) | // We're building a b-tree of the sort merge blocks, we have (cou nt) | |||
// leaves already, so we *know* we need (count-1) merge blocks. | // leaves already, so we *know* we need (count-1) merge blocks. | |||
skipping to change at line 1794 | skipping to change at line 1794 | |||
lower_limit = (sort_ptr_t*) ((SORTP*) lower_limit + m_longs); | lower_limit = (sort_ptr_t*) ((SORTP*) lower_limit + m_longs); | |||
MOVE_32(length, buffer, output); | MOVE_32(length, buffer, output); | |||
output = reinterpret_cast<sort_record*>((sort_ptr_t*) ((SORTP*) o utput + length)); | output = reinterpret_cast<sort_record*>((sort_ptr_t*) ((SORTP*) o utput + length)); | |||
} | } | |||
return (((SORTP*) output) - | return (((SORTP*) output) - | |||
((SORTP*) m_last_record)) / (m_longs - SIZEOF_SR_BCKPTR_I N_LONGS); | ((SORTP*) m_last_record)) / (m_longs - SIZEOF_SR_BCKPTR_I N_LONGS); | |||
} | } | |||
void Sort::orderAndSave() | void Sort::orderAndSave(thread_db* tdbb) | |||
{ | { | |||
/************************************** | /************************************** | |||
* | * | |||
* The memory full of record pointers has been sorted, but more | * The memory full of record pointers has been sorted, but more | |||
* records remain, so the run will have to be written to scratch file. | * records remain, so the run will have to be written to scratch file. | |||
* If target run can be allocated in contiguous chunk of memory then | * If target run can be allocated in contiguous chunk of memory then | |||
* just memcpy records into it. Else call more expensive order() to | * just memcpy records into it. Else call more expensive order() to | |||
* physically rearrange records in sort space and write its run into | * physically rearrange records in sort space and write its run into | |||
* scratch file as one big chunk | * scratch file as one big chunk | |||
* | * | |||
**************************************/ | **************************************/ | |||
EngineCheckout(tdbb, FB_FUNCTION); | ||||
run_control* run = m_runs; | run_control* run = m_runs; | |||
run->run_records = 0; | run->run_records = 0; | |||
sort_record** ptr = m_first_pointer + 1; // 1st ptr is low key | sort_record** ptr = m_first_pointer + 1; // 1st ptr is low key | |||
// m_next_pointer points to the end of pointer memory or the beginning of records | // m_next_pointer points to the end of pointer memory or the beginning of records | |||
while (ptr < m_next_pointer) | while (ptr < m_next_pointer) | |||
{ | { | |||
// If the next pointer is null, it's record has been eliminated a s a | // If the next pointer is null, it's record has been eliminated a s a | |||
// duplicate. This is the only easy case. | // duplicate. This is the only easy case. | |||
if (!(*ptr++)) | if (!(*ptr++)) | |||
skipping to change at line 1852 | skipping to change at line 1854 | |||
mem += key_length; | mem += key_length; | |||
} | } | |||
} | } | |||
else | else | |||
{ | { | |||
order(); | order(); | |||
writeBlock(m_space, run->run_seek, (UCHAR*) m_last_record, run->r un_size); | writeBlock(m_space, run->run_seek, (UCHAR*) m_last_record, run->r un_size); | |||
} | } | |||
} | } | |||
void Sort::putRun() | void Sort::putRun(thread_db* tdbb) | |||
{ | { | |||
/************************************** | /************************************** | |||
* | * | |||
* Memory has been exhausted. Do a sort on what we have and write | * Memory has been exhausted. Do a sort on what we have and write | |||
* it to the scratch file. Keep in mind that since duplicate records | * it to the scratch file. Keep in mind that since duplicate records | |||
* may disappear, the number of records in the run may be less than | * may disappear, the number of records in the run may be less than | |||
* were sorted. | * were sorted. | |||
* | * | |||
**************************************/ | **************************************/ | |||
run_control* run = m_free_runs; | run_control* run = m_free_runs; | |||
skipping to change at line 1880 | skipping to change at line 1882 | |||
memset(run, 0, sizeof(run_control)); | memset(run, 0, sizeof(run_control)); | |||
run->run_next = m_runs; | run->run_next = m_runs; | |||
m_runs = run; | m_runs = run; | |||
run->run_header.rmh_type = RMH_TYPE_RUN; | run->run_header.rmh_type = RMH_TYPE_RUN; | |||
run->run_depth = 0; | run->run_depth = 0; | |||
// Do the in-core sort. The first phase a duplicate handling we be perfor med | // Do the in-core sort. The first phase a duplicate handling we be perfor med | |||
// in "sort". | // in "sort". | |||
sort(); | sortBuffer(tdbb); | |||
// Re-arrange records in physical order so they can be dumped in a single write | // Re-arrange records in physical order so they can be dumped in a single write | |||
// operation | // operation | |||
orderAndSave(); | orderAndSave(tdbb); | |||
} | } | |||
void Sort::sort() | void Sort::sortBuffer(thread_db* tdbb) | |||
{ | { | |||
/************************************** | /************************************** | |||
* | * | |||
* Set up for and call quick sort. Quicksort, by design, doesn't | * Set up for and call quick sort. Quicksort, by design, doesn't | |||
* order partitions of length 2, so make a pass thru the data to | * order partitions of length 2, so make a pass thru the data to | |||
* straighten out pairs. While we at it, if duplicate handling has | * straighten out pairs. While we at it, if duplicate handling has | |||
* been requested, detect and handle them. | * been requested, detect and handle them. | |||
* | * | |||
**************************************/ | **************************************/ | |||
EngineCheckout(tdbb, FB_FUNCTION); | ||||
// First, insert a pointer to the high key | // First, insert a pointer to the high key | |||
*m_next_pointer = reinterpret_cast<sort_record*>(high_key); | *m_next_pointer = reinterpret_cast<sort_record*>(high_key); | |||
// Next, call QuickSort. Keep in mind that the first pointer is the | // Next, call QuickSort. Keep in mind that the first pointer is the | |||
// low key and not a record. | // low key and not a record. | |||
SORTP** j = (SORTP**) (m_first_pointer) + 1; | SORTP** j = (SORTP**) (m_first_pointer) + 1; | |||
const ULONG n = (SORTP**) (m_next_pointer) - j; // calculate # of records | const ULONG n = (SORTP**) (m_next_pointer) - j; // calculate # of records | |||
End of changes. 11 change blocks. | ||||
9 lines changed or deleted | 12 lines changed or added |