00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
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;
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
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
00194
00195 return disk_bytes;
00196 }
00197
00198
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;
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
00240
00241
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
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
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
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
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
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
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
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