Stxxl  1.4.0
include/stxxl/bits/mng/diskallocator.h
Go to the documentation of this file.
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 <dementiev@mpi-sb.mpg.de>
00007  *  Copyright (C) 2007 Johannes Singler <singler@ira.uka.de>
00008  *  Copyright (C) 2009, 2010 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
00009  *
00010  *  Distributed under the Boost Software License, Version 1.0.
00011  *  (See accompanying file LICENSE_1_0.txt or copy at
00012  *  http://www.boost.org/LICENSE_1_0.txt)
00013  **************************************************************************/
00014 
00015 #ifndef STXXL_DISKALLOCATOR_HEADER
00016 #define STXXL_DISKALLOCATOR_HEADER
00017 
00018 #include <vector>
00019 #include <map>
00020 #include <algorithm>
00021 
00022 #include <stxxl/bits/noncopyable.h>
00023 #include <stxxl/bits/parallel.h>
00024 #include <stxxl/bits/mng/bid.h>
00025 #include <stxxl/bits/verbose.h>
00026 #include <stxxl/bits/io/file.h>
00027 
00028 
00029 __STXXL_BEGIN_NAMESPACE
00030 
00031 //! \ingroup mnglayer
00032 //! \{
00033 
00034 class DiskAllocator : private noncopyable
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     typedef std::map<stxxl::int64, stxxl::int64> sortseq;
00049 
00050     stxxl::mutex mutex;
00051     sortseq free_space;
00052     stxxl::int64 free_bytes;
00053     stxxl::int64 disk_bytes;
00054     stxxl::file * storage;
00055     bool autogrow;
00056 
00057     void dump() const;
00058 
00059     void deallocation_error(
00060         stxxl::int64 block_pos, stxxl::int64 block_size,
00061         const sortseq::iterator & pred, const sortseq::iterator & succ) const;
00062 
00063     // expects the mutex to be locked to prevent concurrent access
00064     void add_free_region(stxxl::int64 block_pos, stxxl::int64 block_size);
00065 
00066     // expects the mutex to be locked to prevent concurrent access
00067     void grow_file(stxxl::int64 extend_bytes)
00068     {
00069         if (!extend_bytes)
00070             return;
00071 
00072         storage->set_size(disk_bytes + extend_bytes);
00073         add_free_region(disk_bytes, extend_bytes);
00074         disk_bytes += extend_bytes;
00075     }
00076 
00077 public:
00078     DiskAllocator(stxxl::file * storage, stxxl::int64 disk_size) :
00079         free_bytes(0),
00080         disk_bytes(0),
00081         storage(storage),
00082         autogrow(disk_size == 0)
00083     {
00084         grow_file(disk_size);
00085     }
00086 
00087     inline stxxl::int64 get_free_bytes() const
00088     {
00089         return free_bytes;
00090     }
00091 
00092     inline stxxl::int64 get_used_bytes() const
00093     {
00094         return disk_bytes - free_bytes;
00095     }
00096 
00097     inline stxxl::int64 get_total_bytes() const
00098     {
00099         return disk_bytes;
00100     }
00101 
00102     template <unsigned BLK_SIZE>
00103     void new_blocks(BIDArray<BLK_SIZE> & bids)
00104     {
00105         new_blocks(bids.begin(), bids.end());
00106     }
00107 
00108     template <unsigned BLK_SIZE>
00109     void new_blocks(BID<BLK_SIZE> * begin, BID<BLK_SIZE> * end);
00110 
00111 #if 0
00112     template <unsigned BLK_SIZE>
00113     void delete_blocks(const BIDArray<BLK_SIZE> & bids)
00114     {
00115         for (unsigned i = 0; i < bids.size(); ++i)
00116             delete_block(bids[i]);
00117     }
00118 #endif
00119 
00120     template <unsigned BLK_SIZE>
00121     void delete_block(const BID<BLK_SIZE> & bid)
00122     {
00123         scoped_mutex_lock lock(mutex);
00124 
00125         STXXL_VERBOSE2("DiskAllocator::delete_block<" << BLK_SIZE <<
00126                        ">(pos=" << bid.offset << ", size=" << bid.size <<
00127                        "), free:" << free_bytes << " total:" << disk_bytes);
00128 
00129         add_free_region(bid.offset, bid.size);
00130     }
00131 };
00132 
00133 template <unsigned BLK_SIZE>
00134 void DiskAllocator::new_blocks(BID<BLK_SIZE> * begin, BID<BLK_SIZE> * end)
00135 {
00136     stxxl::int64 requested_size = 0;
00137 
00138     for (typename BIDArray<BLK_SIZE>::iterator cur = begin; cur != end; ++cur)
00139     {
00140         STXXL_VERBOSE2("Asking for a block with size: " << (cur->size));
00141         requested_size += cur->size;
00142     }
00143 
00144     scoped_mutex_lock lock(mutex);
00145 
00146     STXXL_VERBOSE2("DiskAllocator::new_blocks<BLK_SIZE>,  BLK_SIZE = " << BLK_SIZE <<
00147                    ", free:" << free_bytes << " total:" << disk_bytes <<
00148                    ", blocks: " << (end - begin) <<
00149                    " begin: " << static_cast<void *>(begin) <<
00150                    " end: " << static_cast<void *>(end) <<
00151                    ", requested_size=" << requested_size);
00152 
00153     if (free_bytes < requested_size)
00154     {
00155         if (!autogrow) {
00156             STXXL_ERRMSG("External memory block allocation error: " << requested_size <<
00157                          " bytes requested, " << free_bytes <<
00158                          " bytes free. Trying to extend the external memory space...");
00159         }
00160 
00161         grow_file(requested_size);
00162     }
00163 
00164     // dump();
00165 
00166     sortseq::iterator space;
00167     space = std::find_if(free_space.begin(), free_space.end(),
00168                          bind2nd(FirstFit(), requested_size) _STXXL_FORCE_SEQUENTIAL);
00169 
00170     if (space == free_space.end() && requested_size == BLK_SIZE)
00171     {
00172         assert(end - begin == 1);
00173 
00174         STXXL_ERRMSG("Warning: Severe external memory space fragmentation!");
00175         dump();
00176 
00177         STXXL_ERRMSG("External memory block allocation error: " << requested_size <<
00178                      " bytes requested, " << free_bytes <<
00179                      " bytes free. Trying to extend the external memory space...");
00180 
00181         grow_file(BLK_SIZE);
00182 
00183         space = std::find_if(free_space.begin(), free_space.end(),
00184                              bind2nd(FirstFit(), requested_size) _STXXL_FORCE_SEQUENTIAL);
00185     }
00186 
00187     if (space != free_space.end())
00188     {
00189         stxxl::int64 region_pos = (*space).first;
00190         stxxl::int64 region_size = (*space).second;
00191         free_space.erase(space);
00192         if (region_size > requested_size)
00193             free_space[region_pos + requested_size] = region_size - requested_size;
00194 
00195         for (stxxl::int64 pos = region_pos; begin != end; ++begin)
00196         {
00197             begin->offset = pos;
00198             pos += begin->size;
00199         }
00200         free_bytes -= requested_size;
00201         //dump();
00202 
00203         return;
00204     }
00205 
00206     // no contiguous region found
00207     STXXL_VERBOSE1("Warning, when allocating an external memory space, no contiguous region found");
00208     STXXL_VERBOSE1("It might harm the performance");
00209 
00210     assert(requested_size > BLK_SIZE);
00211     assert(end - begin > 1);
00212 
00213     lock.unlock();
00214 
00215     BID<BLK_SIZE> * middle = begin + ((end - begin) / 2);
00216     new_blocks(begin, middle);
00217     new_blocks(middle, end);
00218 }
00219 
00220 //! \}
00221 
00222 __STXXL_END_NAMESPACE
00223 
00224 #endif // !STXXL_DISKALLOCATOR_HEADER
00225 // vim: et:ts=4:sw=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines