Stxxl
1.4.0
|
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