Stxxl  1.4.0
include/stxxl/bits/algo/ksort.h
Go to the documentation of this file.
00001 /***************************************************************************
00002  *  include/stxxl/bits/algo/ksort.h
00003  *
00004  *  Part of the STXXL. See http://stxxl.sourceforge.net
00005  *
00006  *  Copyright (C) 2002 Roman Dementiev <dementiev@mpi-sb.mpg.de>
00007  *  Copyright (C) 2008-2011 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
00008  *
00009  *  Distributed under the Boost Software License, Version 1.0.
00010  *  (See accompanying file LICENSE_1_0.txt or copy at
00011  *  http://www.boost.org/LICENSE_1_0.txt)
00012  **************************************************************************/
00013 
00014 #ifndef STXXL_KSORT_HEADER
00015 #define STXXL_KSORT_HEADER
00016 
00017 #include <stxxl/bits/mng/mng.h>
00018 #include <stxxl/bits/common/rand.h>
00019 #include <stxxl/bits/mng/adaptor.h>
00020 #include <stxxl/bits/common/simple_vector.h>
00021 #include <stxxl/bits/common/switch.h>
00022 #include <stxxl/bits/mng/block_alloc_interleaved.h>
00023 #include <stxxl/bits/algo/intksort.h>
00024 #include <stxxl/bits/algo/adaptor.h>
00025 #include <stxxl/bits/algo/async_schedule.h>
00026 #include <stxxl/bits/mng/block_prefetcher.h>
00027 #include <stxxl/bits/mng/buf_writer.h>
00028 #include <stxxl/bits/algo/run_cursor.h>
00029 #include <stxxl/bits/algo/losertree.h>
00030 #include <stxxl/bits/algo/inmemsort.h>
00031 #include <stxxl/bits/algo/sort_base.h>
00032 #include <stxxl/bits/common/is_sorted.h>
00033 #include <stxxl/bits/common/utils.h>
00034 
00035 
00036 //#define INTERLEAVED_ALLOC
00037 
00038 #define OPT_MERGING
00039 
00040 __STXXL_BEGIN_NAMESPACE
00041 
00042 //! \weakgroup stllayer STL-user layer
00043 //! Layer which groups STL compatible algorithms and containers
00044 
00045 //! \weakgroup stlalgo Algorithms
00046 //! \ingroup stllayer
00047 //! Algorithms with STL-compatible interface
00048 //! \{
00049 
00050 /*! \internal
00051  */
00052 namespace ksort_local
00053 {
00054     template <typename _BIDTp, typename _KeyTp>
00055     struct trigger_entry
00056     {
00057         typedef _BIDTp bid_type;
00058         typedef _KeyTp key_type;
00059 
00060         bid_type bid;
00061         key_type key;
00062 
00063         operator bid_type ()
00064         {
00065             return bid;
00066         }
00067     };
00068 
00069 
00070     template <typename _BIDTp, typename _KeyTp>
00071     inline bool operator < (const trigger_entry<_BIDTp, _KeyTp> & a,
00072                             const trigger_entry<_BIDTp, _KeyTp> & b)
00073     {
00074         return (a.key < b.key);
00075     }
00076 
00077     template <typename _BIDTp, typename _KeyTp>
00078     inline bool operator > (const trigger_entry<_BIDTp, _KeyTp> & a,
00079                             const trigger_entry<_BIDTp, _KeyTp> & b)
00080     {
00081         return (a.key > b.key);
00082     }
00083 
00084     template <typename type, typename key_type1>
00085     struct type_key
00086     {
00087         typedef key_type1 key_type;
00088         key_type key;
00089         type * ptr;
00090 
00091         type_key() { }
00092         type_key(key_type k, type * p) : key(k), ptr(p)
00093         { }
00094     };
00095 
00096     template <typename type, typename key1>
00097     bool operator < (const type_key<type, key1> & a, const type_key<type, key1> & b)
00098     {
00099         return a.key < b.key;
00100     }
00101 
00102     template <typename type, typename key1>
00103     bool operator > (const type_key<type, key1> & a, const type_key<type, key1> & b)
00104     {
00105         return a.key > b.key;
00106     }
00107 
00108 
00109     template <typename block_type, typename bid_type>
00110     struct write_completion_handler
00111     {
00112         block_type * block;
00113         bid_type bid;
00114         request_ptr * req;
00115         void operator () (request * /*completed_req*/)
00116         {
00117             * req = block->read(bid);
00118         }
00119     };
00120 
00121     template <typename type_key_,
00122               typename block_type,
00123               typename run_type,
00124               typename input_bid_iterator,
00125               typename key_extractor>
00126     inline void write_out(
00127         type_key_ * begin,
00128         type_key_ * end,
00129         block_type * & cur_blk,
00130         const block_type * end_blk,
00131         int_type & out_block,
00132         int_type & out_pos,
00133         run_type & run,
00134         write_completion_handler<block_type, typename block_type::bid_type> * & next_read,
00135         typename block_type::bid_type * & bids,
00136         request_ptr * write_reqs,
00137         request_ptr * read_reqs,
00138         input_bid_iterator & it,
00139         key_extractor keyobj)
00140     {
00141         typedef typename block_type::bid_type bid_type;
00142         typedef typename block_type::type type;
00143 
00144         type * elem = cur_blk->elem;
00145         for (type_key_ * p = begin; p < end; p++)
00146         {
00147             elem[out_pos++] = *(p->ptr);
00148 
00149             if (out_pos >= block_type::size)
00150             {
00151                 run[out_block].key = keyobj(*(cur_blk->elem));
00152 
00153                 if (cur_blk < end_blk)
00154                 {
00155                     next_read->block = cur_blk;
00156                     next_read->req = read_reqs + out_block;
00157                     read_reqs[out_block] = NULL;
00158                     bids[out_block] = next_read->bid = *(it++);
00159 
00160                     write_reqs[out_block] = cur_blk->write(
00161                         run[out_block].bid,
00162                         // postpone read of block from next run
00163                         // after write of block from this run
00164                         *(next_read++));
00165                 }
00166                 else
00167                 {
00168                     write_reqs[out_block] = cur_blk->write(run[out_block].bid);
00169                 }
00170 
00171                 cur_blk++;
00172                 elem = cur_blk->elem;
00173                 out_block++;
00174                 out_pos = 0;
00175             }
00176         }
00177     }
00178 
00179     template <
00180         typename block_type,
00181         typename run_type,
00182         typename input_bid_iterator,
00183         typename key_extractor>
00184     void
00185     create_runs(
00186         input_bid_iterator it,
00187         run_type ** runs,
00188         const unsigned_type nruns,
00189         const unsigned_type m2,
00190         key_extractor keyobj)
00191     {
00192         typedef typename block_type::value_type type;
00193         typedef typename block_type::bid_type bid_type;
00194         typedef typename key_extractor::key_type key_type;
00195         typedef type_key<type, key_type> type_key_;
00196 
00197         block_manager * bm = block_manager::get_instance();
00198         block_type * Blocks1 = new block_type[m2];
00199         block_type * Blocks2 = new block_type[m2];
00200         bid_type * bids = new bid_type[m2];
00201         type_key_ * refs1 = new type_key_[m2 * Blocks1->size];
00202         type_key_ * refs2 = new type_key_[m2 * Blocks1->size];
00203         request_ptr * read_reqs = new request_ptr[m2];
00204         request_ptr * write_reqs = new request_ptr[m2];
00205         write_completion_handler<block_type, bid_type> * next_run_reads =
00206             new write_completion_handler<block_type, bid_type>[m2];
00207 
00208         run_type * run;
00209         run = *runs;
00210         int_type run_size = (*runs)->size();
00211         key_type offset = 0;
00212         const int log_k1 = log2_ceil((m2 * block_type::size * sizeof(type_key_) / STXXL_L2_SIZE) ?
00213                                      (m2 * block_type::size * sizeof(type_key_) / STXXL_L2_SIZE) : 2);
00214         const int log_k2 = log2_floor(m2 * Blocks1->size) - log_k1 - 1;
00215         STXXL_VERBOSE("log_k1: " << log_k1 << " log_k2:" << log_k2);
00216         const int_type k1 = 1 << log_k1;
00217         const int_type k2 = 1 << log_k2;
00218         int_type * bucket1 = new int_type[k1];
00219         int_type * bucket2 = new int_type[k2];
00220         int_type i;
00221 
00222         disk_queues::get_instance()->set_priority_op(request_queue::WRITE);
00223 
00224         for (i = 0; i < run_size; i++)
00225         {
00226             bids[i] = *(it++);
00227             read_reqs[i] = Blocks1[i].read(bids[i]);
00228         }
00229 
00230         unsigned_type k = 0;
00231         const int shift1 = sizeof(key_type) * 8 - log_k1;
00232         const int shift2 = shift1 - log_k2;
00233         STXXL_VERBOSE("shift1: " << shift1 << " shift2:" << shift2);
00234 
00235         for ( ; k < nruns; k++)
00236         {
00237             run = runs[k];
00238             run_size = run->size();
00239 
00240             std::fill(bucket1, bucket1 + k1, 0);
00241 
00242             type_key_ * ref_ptr = refs1;
00243             for (i = 0; i < run_size; i++)
00244             {
00245                 if (k)
00246                     write_reqs[i]->wait();
00247 
00248                 read_reqs[i]->wait();
00249                 bm->delete_block(bids[i]);
00250 
00251                 classify_block(Blocks1[i].begin(), Blocks1[i].end(), ref_ptr, bucket1, offset, shift1, keyobj);
00252             }
00253 
00254             exclusive_prefix_sum(bucket1, k1);
00255             classify(refs1, refs1 + run_size * Blocks1->size, refs2, bucket1,
00256                      offset, shift1);
00257 
00258             int_type out_block = 0;
00259             int_type out_pos = 0;
00260             unsigned_type next_run_size = (k < nruns - 1) ? (runs[k + 1]->size()) : 0;
00261 
00262             // recurse on each bucket
00263             type_key_ * c = refs2;
00264             type_key_ * d = refs1;
00265             block_type * cur_blk = Blocks2;
00266             block_type * end_blk = Blocks2 + next_run_size;
00267             write_completion_handler<block_type, bid_type> * next_read = next_run_reads;
00268 
00269             for (i = 0; i < k1; i++)
00270             {
00271                 type_key_ * cEnd = refs2 + bucket1[i];
00272                 type_key_ * dEnd = refs1 + bucket1[i];
00273 
00274                 l1sort(c, cEnd, d, bucket2, k2,
00275                        offset + (key_type(1) << key_type(shift1)) * key_type(i), shift2);         // key_type,key_type,... paranoia
00276 
00277                 write_out(
00278                     d, dEnd, cur_blk, end_blk,
00279                     out_block, out_pos, *run, next_read, bids,
00280                     write_reqs, read_reqs, it, keyobj);
00281 
00282                 c = cEnd;
00283                 d = dEnd;
00284             }
00285 
00286             std::swap(Blocks1, Blocks2);
00287         }
00288 
00289         wait_all(write_reqs, m2);
00290 
00291         delete[] bucket1;
00292         delete[] bucket2;
00293         delete[] refs1;
00294         delete[] refs2;
00295         delete[] Blocks1;
00296         delete[] Blocks2;
00297         delete[] bids;
00298         delete[] next_run_reads;
00299         delete[] read_reqs;
00300         delete[] write_reqs;
00301     }
00302 
00303     template <typename block_type,
00304               typename prefetcher_type,
00305               typename key_extractor>
00306     struct run_cursor2_cmp : public std::binary_function<run_cursor2<block_type, prefetcher_type>, run_cursor2<block_type, prefetcher_type>, bool>
00307     {
00308         typedef run_cursor2<block_type, prefetcher_type> cursor_type;
00309         key_extractor keyobj;
00310         run_cursor2_cmp(key_extractor keyobj_)
00311         {
00312             keyobj = keyobj_;
00313         }
00314         inline bool operator () (const cursor_type & a, const cursor_type & b) const
00315         {
00316             if (UNLIKELY(b.empty()))
00317                 return true;
00318             // sentinel emulation
00319             if (UNLIKELY(a.empty()))
00320                 return false;
00321             //sentinel emulation
00322 
00323             return (keyobj(a.current()) < keyobj(b.current()));
00324         }
00325 
00326     private:
00327         run_cursor2_cmp() { }
00328     };
00329 
00330 
00331     template <typename record_type, typename key_extractor>
00332     class key_comparison : public std::binary_function<record_type, record_type, bool>
00333     {
00334         key_extractor ke;
00335 
00336     public:
00337         key_comparison() { }
00338         key_comparison(key_extractor ke_) : ke(ke_) { }
00339         bool operator () (const record_type & a, const record_type & b) const
00340         {
00341             return ke(a) < ke(b);
00342         }
00343     };
00344 
00345 
00346     template <typename block_type, typename run_type, typename key_ext_>
00347     bool check_ksorted_runs(run_type ** runs,
00348                             unsigned_type nruns,
00349                             unsigned_type m,
00350                             key_ext_ keyext)
00351     {
00352         typedef typename block_type::value_type value_type;
00353 
00354         STXXL_MSG("check_ksorted_runs  Runs: " << nruns);
00355         unsigned_type irun = 0;
00356         for (irun = 0; irun < nruns; ++irun)
00357         {
00358             const unsigned_type nblocks_per_run = runs[irun]->size();
00359             unsigned_type blocks_left = nblocks_per_run;
00360             block_type * blocks = new block_type[m];
00361             request_ptr * reqs = new request_ptr[m];
00362             value_type last = keyext.min_value();
00363 
00364             for (unsigned_type off = 0; off < nblocks_per_run; off += m)
00365             {
00366                 const unsigned_type nblocks = STXXL_MIN(blocks_left, m);
00367                 const unsigned_type nelements = nblocks * block_type::size;
00368                 blocks_left -= nblocks;
00369 
00370                 for (unsigned_type j = 0; j < nblocks; ++j)
00371                 {
00372                     reqs[j] = blocks[j].read((*runs[irun])[off + j].bid);
00373                 }
00374                 wait_all(reqs, reqs + nblocks);
00375 
00376                 if (off && (keyext(blocks[0][0]) < keyext(last)))
00377                 {
00378                     STXXL_MSG("check_sorted_runs  wrong first value in the run " << irun);
00379                     STXXL_MSG(" first value: " << blocks[0][0] << " with key" << keyext(blocks[0][0]));
00380                     STXXL_MSG(" last  value: " << last << " with key" << keyext(last));
00381                     for (unsigned_type k = 0; k < block_type::size; ++k)
00382                         STXXL_MSG("Element " << k << " in the block is :" << blocks[0][k] << " key: " << keyext(blocks[0][k]));
00383                     return false;
00384                 }
00385 
00386                 for (unsigned_type j = 0; j < nblocks; ++j)
00387                 {
00388                     if (keyext(blocks[j][0]) != (*runs[irun])[off + j].key)
00389                     {
00390                         STXXL_MSG("check_sorted_runs  wrong trigger in the run " << irun << " block " << (off + j));
00391                         STXXL_MSG("                   trigger value: " << (*runs[irun])[off + j].key);
00392                         STXXL_MSG("Data in the block:");
00393                         for (unsigned_type k = 0; k < block_type::size; ++k)
00394                             STXXL_MSG("Element " << k << " in the block is :" << blocks[j][k] << " with key: " << keyext(blocks[j][k]));
00395 
00396                         STXXL_MSG("BIDS:");
00397                         for (unsigned_type k = 0; k < nblocks; ++k)
00398                         {
00399                             if (k == j)
00400                                 STXXL_MSG("Bad one comes next.");
00401                             STXXL_MSG("BID " << (off + k) << " is: " << ((*runs[irun])[off + k].bid));
00402                         }
00403 
00404                         return false;
00405                     }
00406                 }
00407                 if (!stxxl::is_sorted(make_element_iterator(blocks, 0),
00408                                       make_element_iterator(blocks, nelements),
00409                                       key_comparison<value_type, key_ext_>()))
00410                 {
00411                     STXXL_MSG("check_sorted_runs  wrong order in the run " << irun);
00412                     STXXL_MSG("Data in blocks:");
00413                     for (unsigned_type j = 0; j < nblocks; ++j)
00414                     {
00415                         for (unsigned_type k = 0; k < block_type::size; ++k)
00416                             STXXL_MSG("     Element " << k << " in block " << (off + j) << " is :" << blocks[j][k] << " with key: " << keyext(blocks[j][k]));
00417                     }
00418                     STXXL_MSG("BIDS:");
00419                     for (unsigned_type k = 0; k < nblocks; ++k)
00420                     {
00421                         STXXL_MSG("BID " << (k + off) << " is: " << ((*runs[irun])[k + off].bid));
00422                     }
00423 
00424                     return false;
00425                 }
00426                 last = blocks[nblocks - 1][block_type::size - 1];
00427             }
00428 
00429             assert(blocks_left == 0);
00430             delete[] reqs;
00431             delete[] blocks;
00432         }
00433 
00434         return true;
00435     }
00436 
00437 
00438     template <typename block_type, typename run_type, typename key_extractor>
00439     void merge_runs(run_type ** in_runs, unsigned_type nruns, run_type * out_run, unsigned_type _m, key_extractor keyobj)
00440     {
00441         typedef block_prefetcher<block_type, typename run_type::iterator> prefetcher_type;
00442         typedef run_cursor2<block_type, prefetcher_type> run_cursor_type;
00443 
00444         unsigned_type i;
00445         run_type consume_seq(out_run->size());
00446 
00447         int_type * prefetch_seq = new int_type[out_run->size()];
00448 
00449         typename run_type::iterator copy_start = consume_seq.begin();
00450         for (i = 0; i < nruns; i++)
00451         {
00452             // TODO: try to avoid copy
00453             copy_start = std::copy(
00454                 in_runs[i]->begin(),
00455                 in_runs[i]->end(),
00456                 copy_start);
00457         }
00458         std::stable_sort(consume_seq.begin(), consume_seq.end() _STXXL_SORT_TRIGGER_FORCE_SEQUENTIAL);
00459 
00460         unsigned disks_number = config::get_instance()->disks_number();
00461 
00462 #ifdef PLAY_WITH_OPT_PREF
00463         const int_type n_write_buffers = 4 * disks_number;
00464 #else
00465         const int_type n_prefetch_buffers = STXXL_MAX(int_type(2 * disks_number), (3 * (int_type(_m) - int_type(nruns)) / 4));
00466         STXXL_VERBOSE("Prefetch buffers " << n_prefetch_buffers);
00467         const int_type n_write_buffers = STXXL_MAX(int_type(2 * disks_number), int_type(_m) - int_type(nruns) - int_type(n_prefetch_buffers));
00468         STXXL_VERBOSE("Write buffers " << n_write_buffers);
00469         // heuristic
00470         const int_type n_opt_prefetch_buffers = 2 * int_type(disks_number) + (3 * (int_type(n_prefetch_buffers) - int_type(2 * disks_number))) / 10;
00471         STXXL_VERBOSE("Prefetch buffers " << n_opt_prefetch_buffers);
00472 #endif
00473 
00474 #if STXXL_SORT_OPTIMAL_PREFETCHING
00475         compute_prefetch_schedule(
00476             consume_seq,
00477             prefetch_seq,
00478             n_opt_prefetch_buffers,
00479             disks_number);
00480 #else
00481         for (i = 0; i < out_run->size(); i++)
00482             prefetch_seq[i] = i;
00483 
00484 #endif
00485 
00486 
00487         prefetcher_type prefetcher(consume_seq.begin(),
00488                                    consume_seq.end(),
00489                                    prefetch_seq,
00490                                    nruns + n_prefetch_buffers);
00491 
00492         buffered_writer<block_type> writer(n_write_buffers, n_write_buffers / 2);
00493 
00494         unsigned_type out_run_size = out_run->size();
00495 
00496         run_cursor2_cmp<block_type, prefetcher_type, key_extractor> cmp(keyobj);
00497         loser_tree<
00498             run_cursor_type,
00499             run_cursor2_cmp<block_type, prefetcher_type, key_extractor> >
00500                 losers(&prefetcher, nruns, cmp);
00501 
00502         block_type * out_buffer = writer.get_free_block();
00503 
00504         for (i = 0; i < out_run_size; i++)
00505         {
00506             losers.multi_merge(out_buffer->elem, out_buffer->elem + block_type::size);
00507             (*out_run)[i].key = keyobj(out_buffer->elem[0]);
00508             out_buffer = writer.write(out_buffer, (*out_run)[i].bid);
00509         }
00510 
00511         delete[] prefetch_seq;
00512 
00513         block_manager * bm = block_manager::get_instance();
00514         for (i = 0; i < nruns; i++)
00515         {
00516             unsigned_type sz = in_runs[i]->size();
00517             for (unsigned_type j = 0; j < sz; j++)
00518                 bm->delete_block((*in_runs[i])[j].bid);
00519 
00520             delete in_runs[i];
00521         }
00522     }
00523 
00524 
00525     template <typename block_type,
00526               typename alloc_strategy,
00527               typename input_bid_iterator,
00528               typename key_extractor>
00529 
00530     simple_vector<trigger_entry<typename block_type::bid_type, typename key_extractor::key_type> > *
00531     ksort_blocks(input_bid_iterator input_bids, unsigned_type _n, unsigned_type _m, key_extractor keyobj)
00532     {
00533         typedef typename block_type::value_type type;
00534         typedef typename key_extractor::key_type key_type;
00535         typedef typename block_type::bid_type bid_type;
00536         typedef trigger_entry<bid_type, typename key_extractor::key_type> trigger_entry_type;
00537         typedef simple_vector<trigger_entry_type> run_type;
00538         typedef typename interleaved_alloc_traits<alloc_strategy>::strategy interleaved_alloc_strategy;
00539 
00540         unsigned_type m2 = div_ceil(_m, 2);
00541         const unsigned_type m2_rf = m2 * block_type::raw_size /
00542                                     (block_type::raw_size + block_type::size * sizeof(type_key<type, key_type>));
00543         STXXL_VERBOSE("Reducing number of blocks in a run from " << m2 << " to " <<
00544                       m2_rf << " due to key size: " << sizeof(typename key_extractor::key_type) << " bytes");
00545         m2 = m2_rf;
00546         unsigned_type full_runs = _n / m2;
00547         unsigned_type partial_runs = ((_n % m2) ? 1 : 0);
00548         unsigned_type nruns = full_runs + partial_runs;
00549         unsigned_type i;
00550 
00551         block_manager * mng = block_manager::get_instance();
00552 
00553         STXXL_VERBOSE("n=" << _n << " nruns=" << nruns << "=" << full_runs << "+" << partial_runs);
00554 
00555         double begin = timestamp(), after_runs_creation, end;
00556 
00557         run_type ** runs = new run_type *[nruns];
00558 
00559         for (i = 0; i < full_runs; i++)
00560             runs[i] = new run_type(m2);
00561 
00562 
00563 #ifdef INTERLEAVED_ALLOC
00564         if (partial_runs)
00565         {
00566             unsigned_type last_run_size = _n - full_runs * m2;
00567             runs[i] = new run_type(last_run_size);
00568 
00569             mng->new_blocks(interleaved_alloc_strategy(nruns, alloc_strategy()),
00570                             RunsToBIDArrayAdaptor2<block_type::raw_size, run_type>
00571                                 (runs, 0, nruns, last_run_size),
00572                             RunsToBIDArrayAdaptor2<block_type::raw_size, run_type>
00573                                 (runs, _n, nruns, last_run_size));
00574         }
00575         else
00576             mng->new_blocks(interleaved_alloc_strategy(nruns, alloc_strategy()),
00577                             RunsToBIDArrayAdaptor<block_type::raw_size, run_type>
00578                                 (runs, 0, nruns),
00579                             RunsToBIDArrayAdaptor<block_type::raw_size, run_type>
00580                                 (runs, _n, nruns));
00581 
00582 #else
00583         if (partial_runs)
00584             runs[i] = new run_type(_n - full_runs * m2);
00585 
00586         for (i = 0; i < nruns; i++)
00587         {
00588             mng->new_blocks(alloc_strategy(), make_bid_iterator(runs[i]->begin()), make_bid_iterator(runs[i]->end()));
00589         }
00590 #endif
00591 
00592         create_runs<block_type,
00593                     run_type,
00594                     input_bid_iterator,
00595                     key_extractor>(input_bids, runs, nruns, m2, keyobj);
00596 
00597         after_runs_creation = timestamp();
00598 
00599         double io_wait_after_rf = stats::get_instance()->get_io_wait_time();
00600 
00601         disk_queues::get_instance()->set_priority_op(request_queue::WRITE);
00602 
00603         const int_type merge_factor = optimal_merge_factor(nruns, _m);
00604         run_type ** new_runs;
00605 
00606         while (nruns > 1)
00607         {
00608             int_type new_nruns = div_ceil(nruns, merge_factor);
00609             STXXL_VERBOSE("Starting new merge phase: nruns: " << nruns <<
00610                           " opt_merge_factor: " << merge_factor << " m:" << _m << " new_nruns: " << new_nruns);
00611 
00612             new_runs = new run_type *[new_nruns];
00613 
00614             int_type runs_left = nruns;
00615             int_type cur_out_run = 0;
00616             int_type blocks_in_new_run = 0;
00617 
00618             while (runs_left > 0)
00619             {
00620                 int_type runs2merge = STXXL_MIN(runs_left, merge_factor);
00621                 blocks_in_new_run = 0;
00622                 for (unsigned_type i = nruns - runs_left; i < (nruns - runs_left + runs2merge); i++)
00623                     blocks_in_new_run += runs[i]->size();
00624 
00625                 // allocate run
00626                 new_runs[cur_out_run++] = new run_type(blocks_in_new_run);
00627                 runs_left -= runs2merge;
00628             }
00629             // allocate blocks in the new runs
00630             if (cur_out_run == 1 && blocks_in_new_run == int_type(_n) && !input_bids->is_managed())
00631             {
00632                 // if we sort a file we can reuse the input bids for the output
00633                 input_bid_iterator cur = input_bids;
00634                 for (int_type i = 0; cur != (input_bids + _n); ++cur)
00635                 {
00636                     (*new_runs[0])[i++].bid = *cur;
00637                 }
00638 
00639                 bid_type & firstBID = (*new_runs[0])[0].bid;
00640                 if (firstBID.is_managed())
00641                 {
00642                     // the first block does not belong to the file
00643                     // need to reallocate it
00644                     mng->new_block(FR(), firstBID);
00645                 }
00646                 bid_type & lastBID = (*new_runs[0])[_n - 1].bid;
00647                 if (lastBID.is_managed())
00648                 {
00649                     // the first block does not belong to the file
00650                     // need to reallocate it
00651                     mng->new_block(FR(), lastBID);
00652                 }
00653             }
00654             else
00655             {
00656                 mng->new_blocks(interleaved_alloc_strategy(new_nruns, alloc_strategy()),
00657                                 RunsToBIDArrayAdaptor2<block_type::raw_size, run_type>(new_runs, 0, new_nruns, blocks_in_new_run),
00658                                 RunsToBIDArrayAdaptor2<block_type::raw_size, run_type>(new_runs, _n, new_nruns, blocks_in_new_run));
00659             }
00660 
00661 
00662             // merge all
00663             runs_left = nruns;
00664             cur_out_run = 0;
00665             while (runs_left > 0)
00666             {
00667                 int_type runs2merge = STXXL_MIN(runs_left, merge_factor);
00668 #if STXXL_CHECK_ORDER_IN_SORTS
00669                 assert((check_ksorted_runs<block_type, run_type, key_extractor>(runs + nruns - runs_left, runs2merge, m2, keyobj)));
00670 #endif
00671                 STXXL_VERBOSE("Merging " << runs2merge << " runs");
00672                 merge_runs<block_type, run_type, key_extractor>(runs + nruns - runs_left,
00673                                                                 runs2merge, *(new_runs + (cur_out_run++)), _m, keyobj);
00674                 runs_left -= runs2merge;
00675             }
00676 
00677             nruns = new_nruns;
00678             delete[] runs;
00679             runs = new_runs;
00680         }
00681 
00682         run_type * result = *runs;
00683         delete[] runs;
00684 
00685         end = timestamp();
00686 
00687         STXXL_VERBOSE("Elapsed time        : " << end - begin << " s. Run creation time: " <<
00688                       after_runs_creation - begin << " s");
00689         STXXL_VERBOSE("Time in I/O wait(rf): " << io_wait_after_rf << " s");
00690         STXXL_VERBOSE(*stats::get_instance());
00691         STXXL_UNUSED(begin + after_runs_creation + end + io_wait_after_rf);
00692 
00693         return result;
00694     }
00695 }
00696 
00697 
00698 /*! \page key_extractor Key extractor concept
00699 
00700    Model of \b Key \b extractor concept must:
00701    - define type \b key_type ,
00702    - provide \b operator() that returns key value of an object of user type
00703    - provide \b max_value method that returns a value that is \b strictly \b greater than all
00704    other objects of user type in respect to the key obtained by this key extractor ,
00705    - provide \b min_value method that returns a value that is \b strictly \b less than all
00706    other objects of user type in respect to the key obtained by this key extractor ,
00707    - operator > , operator <, operator == and operator != on type \b key_type must be defined.
00708    - \b Note: when using unsigned integral types as key, the value 0 cannot
00709    be used as a key value because it would
00710    conflict with the sentinel value returned by \b min_value
00711 
00712    Example: extractor class \b GetWeight, that extracts weight from an \b Edge
00713  \verbatim
00714 
00715    struct Edge
00716    {
00717      unsigned src,dest,weight;
00718      Edge(unsigned s,unsigned d,unsigned w):src(s),dest(d),weight(w){}
00719    };
00720 
00721    struct GetWeight
00722    {
00723     typedef unsigned key_type;
00724     key_type operator() (const Edge & e) const
00725     {
00726         return e.weight;
00727     }
00728     Edge min_value() const { return Edge(0,0,(std::numeric_limits<key_type>::min)()); };
00729     Edge max_value() const { return Edge(0,0,(std::numeric_limits<key_type>::max)()); };
00730    };
00731  \endverbatim
00732 
00733  */
00734 
00735 
00736 //! \brief Sort records with integer keys
00737 //! \param first_ object of model of \c ext_random_access_iterator concept
00738 //! \param last_ object of model of \c ext_random_access_iterator concept
00739 //! \param keyobj \link key_extractor key extractor \endlink object
00740 //! \param M__ amount of memory for internal use (in bytes)
00741 //! \remark Order in the result is non-stable
00742 template <typename ExtIterator_, typename KeyExtractor_>
00743 void ksort(ExtIterator_ first_, ExtIterator_ last_, KeyExtractor_ keyobj, unsigned_type M__)
00744 {
00745     typedef simple_vector<ksort_local::trigger_entry<typename ExtIterator_::bid_type,
00746                                                      typename KeyExtractor_::key_type> > run_type;
00747     typedef typename ExtIterator_::vector_type::value_type value_type;
00748     typedef typename ExtIterator_::block_type block_type;
00749 
00750 
00751     unsigned_type n = 0;
00752     block_manager * mng = block_manager::get_instance();
00753 
00754     first_.flush();
00755 
00756     if ((last_ - first_) * sizeof(value_type) < M__)
00757     {
00758         stl_in_memory_sort(first_, last_, ksort_local::key_comparison<value_type, KeyExtractor_>(keyobj));
00759     }
00760     else
00761     {
00762         assert(2 * block_type::raw_size <= M__);
00763 
00764         if (first_.block_offset())
00765         {
00766             if (last_.block_offset())            // first and last element reside
00767             // not in the beginning of the block
00768             {
00769                 typename ExtIterator_::block_type * first_block = new typename ExtIterator_::block_type;
00770                 typename ExtIterator_::block_type * last_block = new typename ExtIterator_::block_type;
00771                 typename ExtIterator_::bid_type first_bid, last_bid;
00772                 request_ptr req;
00773 
00774                 req = first_block->read(*first_.bid());
00775                 mng->new_block(FR(), first_bid);                // try to overlap
00776                 mng->new_block(FR(), last_bid);
00777                 req->wait();
00778 
00779 
00780                 req = last_block->read(*last_.bid());
00781 
00782                 unsigned_type i = 0;
00783                 for ( ; i < first_.block_offset(); i++)
00784                 {
00785                     first_block->elem[i] = keyobj.min_value();
00786                 }
00787 
00788                 req->wait();
00789 
00790                 req = first_block->write(first_bid);
00791                 for (i = last_.block_offset(); i < block_type::size; i++)
00792                 {
00793                     last_block->elem[i] = keyobj.max_value();
00794                 }
00795 
00796                 req->wait();
00797 
00798                 req = last_block->write(last_bid);
00799 
00800                 n = last_.bid() - first_.bid() + 1;
00801 
00802                 std::swap(first_bid, *first_.bid());
00803                 std::swap(last_bid, *last_.bid());
00804 
00805                 req->wait();
00806 
00807                 delete first_block;
00808                 delete last_block;
00809 
00810                 run_type * out =
00811                     ksort_local::ksort_blocks<
00812                         typename ExtIterator_::block_type,
00813                         typename ExtIterator_::vector_type::alloc_strategy_type,
00814                         typename ExtIterator_::bids_container_iterator,
00815                         KeyExtractor_>
00816                         (first_.bid(), n, M__ / block_type::raw_size, keyobj);
00817 
00818 
00819                 first_block = new typename ExtIterator_::block_type;
00820                 last_block = new typename ExtIterator_::block_type;
00821                 typename ExtIterator_::block_type * sorted_first_block = new typename ExtIterator_::block_type;
00822                 typename ExtIterator_::block_type * sorted_last_block = new typename ExtIterator_::block_type;
00823                 request_ptr * reqs = new request_ptr[2];
00824 
00825                 reqs[0] = first_block->read(first_bid);
00826                 reqs[1] = sorted_first_block->read((*(out->begin())).bid);
00827                 wait_all(reqs, 2);
00828 
00829                 reqs[0] = last_block->read(last_bid);
00830                 reqs[1] = sorted_last_block->read(((*out)[out->size() - 1]).bid);
00831 
00832                 for (i = first_.block_offset(); i < block_type::size; i++)
00833                 {
00834                     first_block->elem[i] = sorted_first_block->elem[i];
00835                 }
00836                 wait_all(reqs, 2);
00837 
00838                 req = first_block->write(first_bid);
00839 
00840                 for (i = 0; i < last_.block_offset(); i++)
00841                 {
00842                     last_block->elem[i] = sorted_last_block->elem[i];
00843                 }
00844 
00845                 req->wait();
00846 
00847 
00848                 req = last_block->write(last_bid);
00849 
00850                 mng->delete_block(out->begin()->bid);
00851                 mng->delete_block((*out)[out->size() - 1].bid);
00852 
00853                 *first_.bid() = first_bid;
00854                 *last_.bid() = last_bid;
00855 
00856                 typename run_type::iterator it = out->begin();
00857                 it++;
00858                 typename ExtIterator_::bids_container_iterator cur_bid = first_.bid();
00859                 cur_bid++;
00860 
00861                 for ( ; cur_bid != last_.bid(); cur_bid++, it++)
00862                 {
00863                     *cur_bid = (*it).bid;
00864                 }
00865 
00866                 delete first_block;
00867                 delete sorted_first_block;
00868                 delete sorted_last_block;
00869                 delete[] reqs;
00870                 delete out;
00871 
00872                 req->wait();
00873 
00874                 delete last_block;
00875             }
00876             else
00877             {
00878                 // first element resides
00879                 // not in the beginning of the block
00880 
00881                 typename ExtIterator_::block_type * first_block = new typename ExtIterator_::block_type;
00882                 typename ExtIterator_::bid_type first_bid;
00883                 request_ptr req;
00884 
00885                 req = first_block->read(*first_.bid());
00886                 mng->new_block(FR(), first_bid);                // try to overlap
00887                 req->wait();
00888 
00889 
00890                 unsigned_type i = 0;
00891                 for ( ; i < first_.block_offset(); i++)
00892                 {
00893                     first_block->elem[i] = keyobj.min_value();
00894                 }
00895 
00896                 req = first_block->write(first_bid);
00897 
00898                 n = last_.bid() - first_.bid();
00899 
00900                 std::swap(first_bid, *first_.bid());
00901 
00902                 req->wait();
00903 
00904                 delete first_block;
00905 
00906                 run_type * out =
00907                     ksort_local::ksort_blocks<
00908                         typename ExtIterator_::block_type,
00909                         typename ExtIterator_::vector_type::alloc_strategy_type,
00910                         typename ExtIterator_::bids_container_iterator,
00911                         KeyExtractor_>
00912                         (first_.bid(), n, M__ / block_type::raw_size, keyobj);
00913 
00914 
00915                 first_block = new typename ExtIterator_::block_type;
00916 
00917                 typename ExtIterator_::block_type * sorted_first_block = new typename ExtIterator_::block_type;
00918 
00919                 request_ptr * reqs = new request_ptr[2];
00920 
00921                 reqs[0] = first_block->read(first_bid);
00922                 reqs[1] = sorted_first_block->read((*(out->begin())).bid);
00923                 wait_all(reqs, 2);
00924 
00925                 for (i = first_.block_offset(); i < block_type::size; i++)
00926                 {
00927                     first_block->elem[i] = sorted_first_block->elem[i];
00928                 }
00929 
00930                 req = first_block->write(first_bid);
00931 
00932                 mng->delete_block(out->begin()->bid);
00933 
00934                 *first_.bid() = first_bid;
00935 
00936                 typename run_type::iterator it = out->begin();
00937                 it++;
00938                 typename ExtIterator_::bids_container_iterator cur_bid = first_.bid();
00939                 cur_bid++;
00940 
00941                 for ( ; cur_bid != last_.bid(); cur_bid++, it++)
00942                 {
00943                     *cur_bid = (*it).bid;
00944                 }
00945 
00946                 *cur_bid = (*it).bid;
00947 
00948                 delete sorted_first_block;
00949                 delete[] reqs;
00950                 delete out;
00951 
00952                 req->wait();
00953 
00954                 delete first_block;
00955             }
00956         }
00957         else
00958         {
00959             if (last_.block_offset())            // last element resides
00960             // not in the beginning of the block
00961             {
00962                 typename ExtIterator_::block_type * last_block = new typename ExtIterator_::block_type;
00963                 typename ExtIterator_::bid_type last_bid;
00964                 request_ptr req;
00965                 unsigned_type i;
00966 
00967                 req = last_block->read(*last_.bid());
00968                 mng->new_block(FR(), last_bid);
00969                 req->wait();
00970 
00971                 for (i = last_.block_offset(); i < block_type::size; i++)
00972                 {
00973                     last_block->elem[i] = keyobj.max_value();
00974                 }
00975 
00976                 req = last_block->write(last_bid);
00977 
00978                 n = last_.bid() - first_.bid() + 1;
00979 
00980                 std::swap(last_bid, *last_.bid());
00981 
00982                 req->wait();
00983 
00984                 delete last_block;
00985 
00986                 run_type * out =
00987                     ksort_local::ksort_blocks<
00988                         typename ExtIterator_::block_type,
00989                         typename ExtIterator_::vector_type::alloc_strategy_type,
00990                         typename ExtIterator_::bids_container_iterator,
00991                         KeyExtractor_>
00992                         (first_.bid(), n, M__ / block_type::raw_size, keyobj);
00993 
00994 
00995                 last_block = new typename ExtIterator_::block_type;
00996                 typename ExtIterator_::block_type * sorted_last_block = new typename ExtIterator_::block_type;
00997                 request_ptr * reqs = new request_ptr[2];
00998 
00999                 reqs[0] = last_block->read(last_bid);
01000                 reqs[1] = sorted_last_block->read(((*out)[out->size() - 1]).bid);
01001                 wait_all(reqs, 2);
01002 
01003                 for (i = 0; i < last_.block_offset(); i++)
01004                 {
01005                     last_block->elem[i] = sorted_last_block->elem[i];
01006                 }
01007 
01008                 req = last_block->write(last_bid);
01009 
01010                 mng->delete_block((*out)[out->size() - 1].bid);
01011 
01012                 *last_.bid() = last_bid;
01013 
01014                 typename run_type::iterator it = out->begin();
01015                 typename ExtIterator_::bids_container_iterator cur_bid = first_.bid();
01016 
01017                 for ( ; cur_bid != last_.bid(); cur_bid++, it++)
01018                 {
01019                     *cur_bid = (*it).bid;
01020                 }
01021 
01022                 delete sorted_last_block;
01023                 delete[] reqs;
01024                 delete out;
01025 
01026                 req->wait();
01027 
01028                 delete last_block;
01029             }
01030             else
01031             {
01032                 // first and last element reside in the beginning of blocks
01033                 n = last_.bid() - first_.bid();
01034 
01035                 run_type * out =
01036                     ksort_local::ksort_blocks<
01037                         typename ExtIterator_::block_type,
01038                         typename ExtIterator_::vector_type::alloc_strategy_type,
01039                         typename ExtIterator_::bids_container_iterator,
01040                         KeyExtractor_>
01041                         (first_.bid(), n, M__ / block_type::raw_size, keyobj);
01042 
01043                 typename run_type::iterator it = out->begin();
01044                 typename ExtIterator_::bids_container_iterator cur_bid = first_.bid();
01045 
01046                 for ( ; cur_bid != last_.bid(); cur_bid++, it++)
01047                 {
01048                     *cur_bid = (*it).bid;
01049                 }
01050 
01051                 delete out;
01052             }
01053         }
01054     }
01055 
01056 #if STXXL_CHECK_ORDER_IN_SORTS
01057     typedef typename ExtIterator_::const_iterator const_iterator;
01058     assert(stxxl::is_sorted(const_iterator(first_), const_iterator(last_),
01059                             ksort_local::key_comparison<value_type, KeyExtractor_>()));
01060 #endif
01061 }
01062 
01063 template <typename record_type>
01064 struct ksort_defaultkey
01065 {
01066     typedef typename record_type::key_type key_type;
01067     key_type operator () (const record_type & obj) const
01068     {
01069         return obj.key();
01070     }
01071     record_type max_value() const
01072     {
01073         return record_type::max_value();
01074     }
01075     record_type min_value() const
01076     {
01077         return record_type::min_value();
01078     }
01079 };
01080 
01081 
01082 //! \brief Sort records with integer keys
01083 //! \param first_ object of model of \c ext_random_access_iterator concept
01084 //! \param last_ object of model of \c ext_random_access_iterator concept
01085 //! \param M__ amount of buffers for internal use
01086 //! \remark Order in the result is non-stable
01087 /*!
01088    Record's type must:
01089    - provide \b max_value method that returns an object that is \b greater than all
01090    other objects of user type ,
01091    - provide \b min_value method that returns an object that is \b less than all
01092    other objects of user type ,
01093    - \b operator \b < that must define strict weak ordering on record's values
01094     (<A HREF="http://www.sgi.com/tech/stl/StrictWeakOrdering.html">see what it is</A>).
01095  */
01096 template <typename ExtIterator_>
01097 void ksort(ExtIterator_ first_, ExtIterator_ last_, unsigned_type M__)
01098 {
01099     ksort(first_, last_,
01100           ksort_defaultkey<typename ExtIterator_::vector_type::value_type>(), M__);
01101 }
01102 
01103 
01104 //! \}
01105 
01106 __STXXL_END_NAMESPACE
01107 
01108 #endif // !STXXL_KSORT_HEADER
01109 // vim: et:ts=4:sw=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines