• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • Examples
  • File List

diskallocator.h

00001 /***************************************************************************
00002  *  include/stxxl/bits/mng/diskallocator.h
00003  *
00004  *  Part of the STXXL. See http://stxxl.sourceforge.net
00005  *
00006  *  Copyright (C) 2002-2004 Roman Dementiev <[email protected]>
00007  *  Copyright (C) 2007 Johannes Singler <[email protected]>
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_DISKALLOCATOR_HEADER
00015 #define STXXL_DISKALLOCATOR_HEADER
00016 
00017 #include <vector>
00018 #include <map>
00019 #include <algorithm>
00020 
00021 #include <stxxl/bits/noncopyable.h>
00022 #include <stxxl/bits/parallel.h>
00023 #include <stxxl/bits/mng/bid.h>
00024 #include <stxxl/bits/verbose.h>
00025 
00026 
00027 __STXXL_BEGIN_NAMESPACE
00028 
00031 
00032 class DiskAllocator : private noncopyable
00033 {
00034     stxxl::mutex mutex;
00035 
00036     typedef std::pair<stxxl::int64, stxxl::int64> place;
00037 
00038     struct FirstFit : public std::binary_function<place, stxxl::int64, bool>
00039     {
00040         bool operator () (
00041             const place & entry,
00042             const stxxl::int64 size) const
00043         {
00044             return (entry.second >= size);
00045         }
00046     };
00047 
00048     struct OffCmp
00049     {
00050         bool operator () (const stxxl::int64 & off1, const stxxl::int64 & off2)
00051         {
00052             return off1 < off2;
00053         }
00054     };
00055 
00056     DiskAllocator()
00057     { }
00058 
00059 protected:
00060     typedef std::map<stxxl::int64, stxxl::int64> sortseq;
00061     sortseq free_space;
00062     //  sortseq used_space;
00063     stxxl::int64 free_bytes;
00064     stxxl::int64 disk_bytes;
00065     bool autogrow;
00066 
00067     void dump();
00068 
00069     void check_corruption(stxxl::int64 region_pos, stxxl::int64 region_size,
00070                           sortseq::iterator pred, sortseq::iterator succ)
00071     {
00072         if (pred != free_space.end())
00073         {
00074             if (pred->first <= region_pos && pred->first + pred->second > region_pos)
00075             {
00076                 STXXL_THROW(bad_ext_alloc, "DiskAllocator::check_corruption", "Error: double deallocation of external memory, trying to deallocate region " << region_pos << " + " << region_size << "  in empty space [" << pred->first << " + " << pred->second << "]");
00077             }
00078         }
00079         if (succ != free_space.end())
00080         {
00081             if (region_pos <= succ->first && region_pos + region_size > succ->first)
00082             {
00083                 STXXL_THROW(bad_ext_alloc, "DiskAllocator::check_corruption", "Error: double deallocation of external memory, trying to deallocate region " << region_pos << " + " << region_size << "  which overlaps empty space [" << succ->first << " + " << succ->second << "]");
00084             }
00085         }
00086     }
00087 
00088 public:
00089     inline DiskAllocator(stxxl::int64 disk_size);
00090 
00091     inline stxxl::int64 get_free_bytes() const
00092     {
00093         return free_bytes;
00094     }
00095 
00096     inline stxxl::int64 get_used_bytes() const
00097     {
00098         return disk_bytes - free_bytes;
00099     }
00100 
00101     inline stxxl::int64 get_total_bytes() const
00102     {
00103         return disk_bytes;
00104     }
00105 
00106     template <unsigned BLK_SIZE>
00107     stxxl::int64 new_blocks(BIDArray<BLK_SIZE> & bids);
00108 
00109     template <unsigned BLK_SIZE>
00110     stxxl::int64 new_blocks(BID<BLK_SIZE> * begin,
00111                             BID<BLK_SIZE> * end);
00112 #if 0
00113     template <unsigned BLK_SIZE>
00114     void delete_blocks(const BIDArray<BLK_SIZE> & bids);
00115 #endif
00116     template <unsigned BLK_SIZE>
00117     void delete_block(const BID<BLK_SIZE> & bid);
00118 };
00119 
00120 DiskAllocator::DiskAllocator(stxxl::int64 disk_size) :
00121     free_bytes(disk_size),
00122     disk_bytes(disk_size),
00123     autogrow(disk_size == 0)
00124 {
00125     free_space[0] = disk_size;
00126 }
00127 
00128 
00129 template <unsigned BLK_SIZE>
00130 stxxl::int64 DiskAllocator::new_blocks(BIDArray<BLK_SIZE> & bids)
00131 {
00132     return new_blocks(bids.begin(), bids.end());
00133 }
00134 
00135 template <unsigned BLK_SIZE>
00136 stxxl::int64 DiskAllocator::new_blocks(BID<BLK_SIZE> * begin,
00137                                        BID<BLK_SIZE> * end)
00138 {
00139     scoped_mutex_lock lock(mutex);
00140 
00141     STXXL_VERBOSE2("DiskAllocator::new_blocks<BLK_SIZE>,  BLK_SIZE = " << BLK_SIZE <<
00142                    ", free:" << free_bytes << " total:" << disk_bytes <<
00143                    ", blocks: " << (end - begin) <<
00144                    " begin: " << ((void *)(begin)) << " end: " << ((void *)(end)));
00145 
00146     stxxl::int64 requested_size = 0;
00147 
00148     typename BIDArray<BLK_SIZE>::iterator cur = begin;
00149     for ( ; cur != end; ++cur)
00150     {
00151         STXXL_VERBOSE2("Asking for a block with size: " << (cur->size));
00152         requested_size += cur->size;
00153     }
00154 
00155     if (free_bytes < requested_size)
00156     {
00157         if (!autogrow) {
00158             STXXL_ERRMSG("External memory block allocation error: " << requested_size <<
00159                          " bytes requested, " << free_bytes <<
00160                          " bytes free. Trying to extend the external memory space...");
00161         }
00162 
00163         begin->offset = disk_bytes; // allocate at the end
00164         for (++begin; begin != end; ++begin)
00165         {
00166             begin->offset = (begin - 1)->offset + (begin - 1)->size;
00167         }
00168         disk_bytes += requested_size;
00169 
00170         return disk_bytes;
00171     }
00172 
00173     // dump();
00174 
00175     sortseq::iterator space =
00176         std::find_if(free_space.begin(), free_space.end(),
00177                      bind2nd(FirstFit(), requested_size) _STXXL_FORCE_SEQUENTIAL);
00178 
00179     if (space != free_space.end())
00180     {
00181         stxxl::int64 region_pos = (*space).first;
00182         stxxl::int64 region_size = (*space).second;
00183         free_space.erase(space);
00184         if (region_size > requested_size)
00185             free_space[region_pos + requested_size] = region_size - requested_size;
00186 
00187         begin->offset = region_pos;
00188         for (++begin; begin != end; ++begin)
00189         {
00190             begin->offset = (begin - 1)->offset + (begin - 1)->size;
00191         }
00192         free_bytes -= requested_size;
00193         //dump();
00194 
00195         return disk_bytes;
00196     }
00197 
00198     // no contiguous region found
00199     STXXL_VERBOSE1("Warning, when allocating an external memory space, no contiguous region found");
00200     STXXL_VERBOSE1("It might harm the performance");
00201     if (requested_size == BLK_SIZE)
00202     {
00203         assert(end - begin == 1);
00204 
00205         STXXL_ERRMSG("Warning: Severe external memory space fragmentation!");
00206         dump();
00207 
00208         STXXL_ERRMSG("External memory block allocation error: " << requested_size <<
00209                      " bytes requested, " << free_bytes <<
00210                      " bytes free. Trying to extend the external memory space...");
00211 
00212         begin->offset = disk_bytes; // allocate at the end
00213         disk_bytes += BLK_SIZE;
00214 
00215         return disk_bytes;
00216     }
00217 
00218     assert(requested_size > BLK_SIZE);
00219     assert(end - begin > 1);
00220 
00221     lock.unlock();
00222 
00223     typename  BIDArray<BLK_SIZE>::iterator middle = begin + ((end - begin) / 2);
00224     new_blocks(begin, middle);
00225     new_blocks(middle, end);
00226 
00227     return disk_bytes;
00228 }
00229 
00230 
00231 template <unsigned BLK_SIZE>
00232 void DiskAllocator::delete_block(const BID<BLK_SIZE> & bid)
00233 {
00234     scoped_mutex_lock lock(mutex);
00235 
00236     STXXL_VERBOSE2("DiskAllocator::delete_block<BLK_SIZE>,  BLK_SIZE = " << BLK_SIZE
00237                                                                          << ", free:" << free_bytes << " total:" << disk_bytes);
00238     STXXL_VERBOSE2("Deallocating a block with size: " << bid.size);
00239     //assert(bid.size);
00240 
00241     //dump();
00242     stxxl::int64 region_pos = bid.offset;
00243     stxxl::int64 region_size = bid.size;
00244     STXXL_VERBOSE2("Deallocating a block with size: " << region_size << " position: " << region_pos);
00245     if (!free_space.empty())
00246     {
00247         sortseq::iterator succ = free_space.upper_bound(region_pos);
00248         sortseq::iterator pred = succ;
00249         if (pred != free_space.begin())
00250             pred--;
00251         check_corruption(region_pos, region_size, pred, succ);
00252         if (succ == free_space.end())
00253         {
00254             if (pred == free_space.end())
00255             {
00256                 STXXL_ERRMSG("Error deallocating block at " << bid.offset << " size " << bid.size);
00257                 STXXL_ERRMSG(((pred == succ) ? "pred==succ" : "pred!=succ"));
00258                 STXXL_ERRMSG(((pred == free_space.begin()) ? "pred==free_space.begin()" : "pred!=free_space.begin()"));
00259                 STXXL_ERRMSG(((pred == free_space.end()) ? "pred==free_space.end()" : "pred!=free_space.end()"));
00260                 STXXL_ERRMSG(((succ == free_space.begin()) ? "succ==free_space.begin()" : "succ!=free_space.begin()"));
00261                 STXXL_ERRMSG(((succ == free_space.end()) ? "succ==free_space.end()" : "succ!=free_space.end()"));
00262                 dump();
00263                 assert(pred != free_space.end());
00264             }
00265             if ((*pred).first + (*pred).second == region_pos)
00266             {
00267                 // coalesce with predecessor
00268                 region_size += (*pred).second;
00269                 region_pos = (*pred).first;
00270                 free_space.erase(pred);
00271             }
00272         }
00273         else
00274         {
00275             if (free_space.size() > 1)
00276             {
00277 #if 0
00278                 if (pred == succ)
00279                 {
00280                     STXXL_ERRMSG("Error deallocating block at " << bid.offset << " size " << bid.size);
00281                     STXXL_ERRMSG(((pred == succ) ? "pred==succ" : "pred!=succ"));
00282                     STXXL_ERRMSG(((pred == free_space.begin()) ? "pred==free_space.begin()" : "pred!=free_space.begin()"));
00283                     STXXL_ERRMSG(((pred == free_space.end()) ? "pred==free_space.end()" : "pred!=free_space.end()"));
00284                     STXXL_ERRMSG(((succ == free_space.begin()) ? "succ==free_space.begin()" : "succ!=free_space.begin()"));
00285                     STXXL_ERRMSG(((succ == free_space.end()) ? "succ==free_space.end()" : "succ!=free_space.end()"));
00286                     dump();
00287                     assert(pred != succ);
00288                 }
00289 #endif
00290                 bool succ_is_not_the_first = (succ != free_space.begin());
00291                 if ((*succ).first == region_pos + region_size)
00292                 {
00293                     // coalesce with successor
00294                     region_size += (*succ).second;
00295                     free_space.erase(succ);
00296                 }
00297                 if (succ_is_not_the_first)
00298                 {
00299                     if (pred == free_space.end())
00300                     {
00301                         STXXL_ERRMSG("Error deallocating block at " << bid.offset << " size " << bid.size);
00302                         STXXL_ERRMSG(((pred == succ) ? "pred==succ" : "pred!=succ"));
00303                         STXXL_ERRMSG(((pred == free_space.begin()) ? "pred==free_space.begin()" : "pred!=free_space.begin()"));
00304                         STXXL_ERRMSG(((pred == free_space.end()) ? "pred==free_space.end()" : "pred!=free_space.end()"));
00305                         STXXL_ERRMSG(((succ == free_space.begin()) ? "succ==free_space.begin()" : "succ!=free_space.begin()"));
00306                         STXXL_ERRMSG(((succ == free_space.end()) ? "succ==free_space.end()" : "succ!=free_space.end()"));
00307                         dump();
00308                         assert(pred != free_space.end());
00309                     }
00310                     if ((*pred).first + (*pred).second == region_pos)
00311                     {
00312                         // coalesce with predecessor
00313                         region_size += (*pred).second;
00314                         region_pos = (*pred).first;
00315                         free_space.erase(pred);
00316                     }
00317                 }
00318             }
00319             else
00320             {
00321                 if ((*succ).first == region_pos + region_size)
00322                 {
00323                     // coalesce with successor
00324                     region_size += (*succ).second;
00325                     free_space.erase(succ);
00326                 }
00327             }
00328         }
00329     }
00330 
00331     free_space[region_pos] = region_size;
00332     free_bytes += stxxl::int64(bid.size);
00333 
00334     //dump();
00335 }
00336 
00337 #if 0
00338 template <unsigned BLK_SIZE>
00339 void DiskAllocator::delete_blocks(const BIDArray<BLK_SIZE> & bids)
00340 {
00341     STXXL_VERBOSE2("DiskAllocator::delete_blocks<BLK_SIZE> BLK_SIZE=" << BLK_SIZE <<
00342                    ", free:" << free_bytes << " total:" << disk_bytes);
00343 
00344     unsigned i = 0;
00345     for ( ; i < bids.size(); ++i)
00346     {
00347         stxxl::int64 region_pos = bids[i].offset;
00348         stxxl::int64 region_size = bids[i].size;
00349         STXXL_VERBOSE2("Deallocating a block with size: " << region_size);
00350         assert(bids[i].size);
00351 
00352         if (!free_space.empty())
00353         {
00354             sortseq::iterator succ =
00355                 free_space.upper_bound(region_pos);
00356             sortseq::iterator pred = succ;
00357             pred--;
00358 
00359             if (succ != free_space.end()
00360                 && (*succ).first == region_pos + region_size)
00361             {
00362                 // coalesce with successor
00363 
00364                 region_size += (*succ).second;
00365                 free_space.erase(succ);
00366             }
00367             if (pred != free_space.end()
00368                 && (*pred).first + (*pred).second == region_pos)
00369             {
00370                 // coalesce with predecessor
00371 
00372                 region_size += (*pred).second;
00373                 region_pos = (*pred).first;
00374                 free_space.erase(pred);
00375             }
00376         }
00377         free_space[region_pos] = region_size;
00378     }
00379     for (i = 0; i < bids.size(); ++i)
00380         free_bytes += stxxl::int64(bids[i].size);
00381 }
00382 #endif
00383 
00385 
00386 __STXXL_END_NAMESPACE
00387 
00388 #endif // !STXXL_DISKALLOCATOR_HEADER
00389 // vim: et:ts=4:sw=4

Generated by  doxygen 1.7.1