00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef STXXL_MNG_HEADER
00016 #define STXXL_MNG_HEADER
00017
00018 #include <memory>
00019 #include <iostream>
00020 #include <fstream>
00021 #include <vector>
00022 #include <list>
00023 #include <map>
00024 #include <algorithm>
00025 #include <string>
00026 #include <cstdlib>
00027
00028 #ifdef STXXL_BOOST_CONFIG
00029 #include <boost/config.hpp>
00030 #endif
00031
00032 #ifdef BOOST_MSVC
00033 #include <memory.h>
00034 #endif
00035
00036 #include <stxxl/io>
00037 #include <stxxl/bits/noncopyable.h>
00038 #include <stxxl/bits/common/rand.h>
00039 #include <stxxl/bits/common/aligned_alloc.h>
00040 #include <stxxl/bits/common/debug.h>
00041
00042
00043 __STXXL_BEGIN_NAMESPACE
00044
00049
00051
00053 template <unsigned SIZE>
00054 struct BID
00055 {
00056 enum
00057 {
00058 size = SIZE,
00059 t_size = SIZE
00060 };
00061 file * storage;
00062 stxxl::int64 offset;
00063 BID() : storage(NULL), offset(0) { }
00064 bool valid() const
00065 {
00066 return storage;
00067 }
00068 BID(file * s, stxxl::int64 o) : storage(s), offset(o) { }
00069 BID(const BID & obj) : storage(obj.storage), offset(obj.offset) { }
00070 template <unsigned BlockSize>
00071 explicit BID(const BID<BlockSize> & obj) : storage(obj.storage), offset(obj.offset) { }
00072 };
00073
00074
00076
00078 template <>
00079 struct BID<0>
00080 {
00081 file * storage;
00082 stxxl::int64 offset;
00083 unsigned size;
00084 enum
00085 {
00086 t_size = 0
00087 };
00088 BID() : storage(NULL), offset(0), size(0) { }
00089 BID(file * f, stxxl::int64 o, unsigned s) : storage(f), offset(o), size(s) { }
00090 bool valid() const
00091 {
00092 return storage;
00093 }
00094 };
00095
00096 template <unsigned blk_sz>
00097 bool operator == (const BID<blk_sz> & a, const BID<blk_sz> & b)
00098 {
00099 return (a.storage == b.storage) && (a.offset == b.offset) && (a.size == b.size);
00100 }
00101
00102 template <unsigned blk_sz>
00103 bool operator != (const BID<blk_sz> & a, const BID<blk_sz> & b)
00104 {
00105 return (a.storage != b.storage) || (a.offset != b.offset) || (a.size != b.size);
00106 }
00107
00108
00109 template <unsigned blk_sz>
00110 std::ostream & operator << (std::ostream & s, const BID<blk_sz> & bid)
00111 {
00112 s << " storage file addr: " << bid.storage;
00113 s << " offset: " << bid.offset;
00114 s << " size: " << bid.size;
00115 return s;
00116 }
00117
00118
00119 template <unsigned bytes>
00120 class filler_struct__
00121 {
00122 typedef unsigned char byte_type;
00123 byte_type filler_array_[bytes];
00124
00125 public:
00126 filler_struct__() { STXXL_VERBOSE2("filler_struct__ is allocated"); }
00127 };
00128
00129 template <>
00130 class filler_struct__<0>
00131 {
00132 typedef unsigned char byte_type;
00133
00134 public:
00135 filler_struct__() { STXXL_VERBOSE2("filler_struct__ is allocated"); }
00136 };
00137
00139 template <class T, unsigned Size_>
00140 class element_block
00141 {
00142 public:
00143 typedef T type;
00144 typedef T value_type;
00145 typedef T & reference;
00146 typedef const T & const_reference;
00147 typedef type * pointer;
00148 typedef pointer iterator;
00149 typedef const type * const_iterator;
00150
00151 enum
00152 {
00153 size = Size_
00154 };
00155
00157 T elem[size];
00158
00159 element_block() { STXXL_VERBOSE2("element_block is allocated"); }
00160
00162 reference operator [] (int i)
00163 {
00164 return elem[i];
00165 }
00166
00168 iterator begin()
00169 {
00170 return elem;
00171 }
00173 const_iterator begin() const
00174 {
00175 return elem;
00176 }
00178 iterator end()
00179 {
00180 return elem + size;
00181 }
00183 const_iterator end() const
00184 {
00185 return elem + size;
00186 }
00187 };
00188
00190 template <class T, unsigned Size_, unsigned RawSize_, unsigned NBids_ = 0>
00191 class block_w_bids : public element_block<T, Size_>
00192 {
00193 public:
00194 enum
00195 {
00196 raw_size = RawSize_,
00197 nbids = NBids_
00198 };
00199 typedef BID<raw_size> bid_type;
00200
00202 bid_type ref[nbids];
00203
00205 bid_type & operator () (int i)
00206 {
00207 return ref[i];
00208 }
00209
00210 block_w_bids() { STXXL_VERBOSE2("block_w_bids is allocated"); }
00211 };
00212
00213 template <class T, unsigned Size_, unsigned RawSize_>
00214 class block_w_bids<T, Size_, RawSize_, 0>: public element_block<T, Size_>
00215 {
00216 public:
00217 enum
00218 {
00219 raw_size = RawSize_,
00220 nbids = 0
00221 };
00222 typedef BID<raw_size> bid_type;
00223
00224 block_w_bids() { STXXL_VERBOSE2("block_w_bids is allocated"); }
00225 };
00226
00228 template <class T_, unsigned RawSize_, unsigned NBids_, class InfoType_ = void>
00229 class block_w_info :
00230 public block_w_bids<T_, ((RawSize_ - sizeof(BID<RawSize_>) * NBids_ - sizeof(InfoType_)) / sizeof(T_)), RawSize_, NBids_>
00231 {
00232 public:
00234 typedef InfoType_ info_type;
00235
00237 info_type info;
00238
00239 enum { size = ((RawSize_ - sizeof(BID<RawSize_>) * NBids_ - sizeof(InfoType_)) / sizeof(T_)) };
00240
00241 public:
00242 block_w_info() { STXXL_VERBOSE2("block_w_info is allocated"); }
00243 };
00244
00245 template <class T_, unsigned RawSize_, unsigned NBids_>
00246 class block_w_info<T_, RawSize_, NBids_, void>:
00247 public block_w_bids<T_, ((RawSize_ - sizeof(BID<RawSize_>) * NBids_) / sizeof(T_)), RawSize_, NBids_>
00248 {
00249 public:
00250 typedef void info_type;
00251 enum { size = ((RawSize_ - sizeof(BID<RawSize_>) * NBids_) / sizeof(T_)) };
00252
00253 public:
00254 block_w_info() { STXXL_VERBOSE2("block_w_info is allocated"); }
00255 };
00256
00258
00271 template <unsigned RawSize_, class T_, unsigned NRef_ = 0, class InfoType_ = void>
00272 class typed_block :
00273 public block_w_info<T_, RawSize_, NRef_, InfoType_>,
00274 public filler_struct__<(RawSize_ - sizeof(block_w_info<T_, RawSize_, NRef_, InfoType_>))>
00275 {
00276 public:
00277 typedef T_ type;
00278 typedef T_ value_type;
00279 typedef T_ & reference;
00280 typedef const T_ & const_reference;
00281 typedef type * pointer;
00282 typedef pointer iterator;
00283 typedef type const * const_iterator;
00284
00285 enum { has_filler = (RawSize_ != sizeof(block_w_info<T_, RawSize_, NRef_, InfoType_>)) };
00286
00287 typedef BID<RawSize_> bid_type;
00288
00289 typed_block()
00290 {
00291 STXXL_VERBOSE2("typed_block is allocated");
00292 }
00293
00294 enum
00295 {
00296 raw_size = RawSize_,
00297 size = block_w_info<T_, RawSize_, NRef_, InfoType_>::size
00298 };
00299
00305 request_ptr write(const BID<raw_size> & bid,
00306 completion_handler on_cmpl = default_completion_handler())
00307 {
00308 return bid.storage->awrite(
00309 this,
00310 bid.offset,
00311 raw_size,
00312 on_cmpl);
00313 }
00314
00320 request_ptr read(const BID<raw_size> & bid,
00321 completion_handler on_cmpl = default_completion_handler())
00322 {
00323 return bid.storage->aread(this, bid.offset, raw_size, on_cmpl);
00324 }
00325
00326 static void * operator new[] (size_t bytes)
00327 {
00328 unsigned_type meta_info_size = bytes % raw_size;
00329 STXXL_VERBOSE1("typed::block operator new[]: Meta info size: " << meta_info_size);
00330
00331 void * result = aligned_alloc<BLOCK_ALIGN>(bytes, meta_info_size);
00332 #ifdef STXXL_VALGRIND_TYPED_BLOCK_INITIALIZE_ZERO
00333 memset(result, 0, bytes);
00334 #endif
00335 char * tmp = (char *)result;
00336 debugmon::get_instance()->block_allocated(tmp, tmp + bytes, RawSize_);
00337 tmp += RawSize_;
00338 while (tmp < ((char *)result) + bytes)
00339 {
00340 debugmon::get_instance()->block_allocated(tmp, ((char *)result) + bytes, RawSize_);
00341 tmp += RawSize_;
00342 }
00343 return result;
00344 }
00345
00346 static void * operator new (size_t bytes)
00347 {
00348 unsigned_type meta_info_size = bytes % raw_size;
00349 STXXL_VERBOSE1("typed::block operator new: Meta info size: " << meta_info_size);
00350
00351 void * result = aligned_alloc<BLOCK_ALIGN>(bytes, meta_info_size);
00352 #ifdef STXXL_VALGRIND_TYPED_BLOCK_INITIALIZE_ZERO
00353 memset(result, 0, bytes);
00354 #endif
00355 char * tmp = (char *)result;
00356 debugmon::get_instance()->block_allocated(tmp, tmp + bytes, RawSize_);
00357 tmp += RawSize_;
00358 while (tmp < ((char *)result) + bytes)
00359 {
00360 debugmon::get_instance()->block_allocated(tmp, ((char *)result) + bytes, RawSize_);
00361 tmp += RawSize_;
00362 }
00363 return result;
00364 }
00365
00366 static void * operator new (size_t , void * ptr)
00367 {
00368 return ptr;
00369 }
00370
00371 static void operator delete[] (void * ptr)
00372 {
00373 debugmon::get_instance()->block_deallocated((char *)ptr);
00374 aligned_dealloc<BLOCK_ALIGN>(ptr);
00375 }
00376
00377 static void operator delete (void * ptr)
00378 {
00379 debugmon::get_instance()->block_deallocated((char *)ptr);
00380 aligned_dealloc<BLOCK_ALIGN>(ptr);
00381 }
00382
00383 static void operator delete (void *, void *)
00384 { }
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 };
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 template <unsigned BLK_SIZE>
00409 class BIDArray : private noncopyable
00410 {
00411 protected:
00412 unsigned_type _size;
00413 BID<BLK_SIZE> * array;
00414
00415 public:
00416 typedef BID<BLK_SIZE> & reference;
00417 typedef BID<BLK_SIZE> * iterator;
00418 typedef const BID<BLK_SIZE> * const_iterator;
00419 BIDArray() : _size(0), array(NULL)
00420 { }
00421 iterator begin()
00422 {
00423 return array;
00424 }
00425 iterator end()
00426 {
00427 return array + _size;
00428 }
00429
00430 BIDArray(unsigned_type size) : _size(size)
00431 {
00432 array = new BID<BLK_SIZE>[size];
00433 }
00434 unsigned_type size() const
00435 {
00436 return _size;
00437 }
00438 reference operator [] (int_type i)
00439 {
00440 return array[i];
00441 }
00442 void resize(unsigned_type newsize)
00443 {
00444 if (array)
00445 {
00446 STXXL_MSG("Warning: resizing nonempty BIDArray");
00447 BID<BLK_SIZE> * tmp = array;
00448 array = new BID<BLK_SIZE>[newsize];
00449 memcpy((void *)array, (void *)tmp,
00450 sizeof(BID<BLK_SIZE>) * (STXXL_MIN(_size, newsize)));
00451 delete[] tmp;
00452 _size = newsize;
00453 }
00454 else
00455 {
00456 array = new BID<BLK_SIZE>[newsize];
00457 _size = newsize;
00458 }
00459 }
00460 ~BIDArray()
00461 {
00462 if (array)
00463 delete[] array;
00464 }
00465 };
00466
00467
00468 class DiskAllocator : private noncopyable
00469 {
00470 #ifdef STXXL_BOOST_THREADS
00471 boost::mutex mutex;
00472 #else
00473 stxxl::mutex mutex;
00474 #endif
00475
00476 typedef std::pair<stxxl::int64, stxxl::int64> place;
00477 struct FirstFit : public std::binary_function<place, stxxl::int64, bool>
00478 {
00479 bool operator () (
00480 const place & entry,
00481 const stxxl::int64 size) const
00482 {
00483 return (entry.second >= size);
00484 }
00485 };
00486 struct OffCmp
00487 {
00488 bool operator () (const stxxl::int64 & off1, const stxxl::int64 & off2)
00489 {
00490 return off1 < off2;
00491 }
00492 };
00493
00494 DiskAllocator()
00495 { }
00496
00497 protected:
00498 typedef std::map<stxxl::int64, stxxl::int64> sortseq;
00499 sortseq free_space;
00500
00501 stxxl::int64 free_bytes;
00502 stxxl::int64 disk_bytes;
00503
00504 void dump();
00505
00506 void check_corruption(stxxl::int64 region_pos, stxxl::int64 region_size,
00507 sortseq::iterator pred, sortseq::iterator succ)
00508 {
00509 if (pred != free_space.end())
00510 {
00511 if (pred->first <= region_pos && pred->first + pred->second > region_pos)
00512 {
00513 STXXL_THROW(bad_ext_alloc, "DiskAllocator::check_corruption", "Error: double deallocation of external memory " <<
00514 "System info: P " << pred->first << " " << pred->second << " " << region_pos);
00515 }
00516 }
00517 if (succ != free_space.end())
00518 {
00519 if (region_pos <= succ->first && region_pos + region_size > succ->first)
00520 {
00521 STXXL_THROW(bad_ext_alloc, "DiskAllocator::check_corruption", "Error: double deallocation of external memory "
00522 << "System info: S " << region_pos << " " << region_size << " " << succ->first);
00523 }
00524 }
00525 }
00526
00527 public:
00528 inline DiskAllocator(stxxl::int64 disk_size);
00529
00530 inline stxxl::int64 get_free_bytes() const
00531 {
00532 return free_bytes;
00533 }
00534 inline stxxl::int64 get_used_bytes() const
00535 {
00536 return disk_bytes - free_bytes;
00537 }
00538 inline stxxl::int64 get_total_bytes() const
00539 {
00540 return disk_bytes;
00541 }
00542
00543 template <unsigned BLK_SIZE>
00544 stxxl::int64 new_blocks(BIDArray<BLK_SIZE> & bids);
00545
00546 template <unsigned BLK_SIZE>
00547 stxxl::int64 new_blocks(BID<BLK_SIZE> * begin,
00548 BID<BLK_SIZE> * end);
00549
00550
00551
00552 template <unsigned BLK_SIZE>
00553 void delete_block(const BID<BLK_SIZE> & bid);
00554 };
00555
00556 DiskAllocator::DiskAllocator(stxxl::int64 disk_size) :
00557 free_bytes(disk_size),
00558 disk_bytes(disk_size)
00559 {
00560 free_space[0] = disk_size;
00561 }
00562
00563
00564 template <unsigned BLK_SIZE>
00565 stxxl::int64 DiskAllocator::new_blocks(BIDArray<BLK_SIZE> & bids)
00566 {
00567 return new_blocks(bids.begin(), bids.end());
00568 }
00569
00570 template <unsigned BLK_SIZE>
00571 stxxl::int64 DiskAllocator::new_blocks(BID<BLK_SIZE> * begin,
00572 BID<BLK_SIZE> * end)
00573 {
00574 #ifdef STXXL_BOOST_THREADS
00575 boost::mutex::scoped_lock lock(mutex);
00576 #else
00577 mutex.lock();
00578 #endif
00579
00580 STXXL_VERBOSE2("DiskAllocator::new_blocks<BLK_SIZE>, BLK_SIZE = " << BLK_SIZE
00581 << ", free:" << free_bytes << " total:" << disk_bytes <<
00582 " begin: " << ((void *)(begin)) << " end: " << ((void *)(end)));
00583
00584 stxxl::int64 requested_size = 0;
00585
00586 typename BIDArray<BLK_SIZE>::iterator cur = begin;
00587 for ( ; cur != end; ++cur)
00588 {
00589 STXXL_VERBOSE2("Asking for a block with size: " << (cur->size));
00590 requested_size += cur->size;
00591 }
00592
00593 if (free_bytes < requested_size)
00594 {
00595 STXXL_ERRMSG("External memory block allocation error: " << requested_size <<
00596 " bytes requested, " << free_bytes <<
00597 " bytes free. Trying to extend the external memory space...");
00598
00599
00600 begin->offset = disk_bytes;
00601 for (++begin; begin != end; ++begin)
00602 {
00603 begin->offset = (begin - 1)->offset + (begin - 1)->size;
00604 }
00605 disk_bytes += requested_size;
00606
00607 #ifndef STXXL_BOOST_THREADS
00608 mutex.unlock();
00609 #endif
00610
00611 return disk_bytes;
00612 }
00613
00614
00615
00616 sortseq::iterator space =
00617 std::find_if(free_space.begin(), free_space.end(),
00618 bind2nd(FirstFit(), requested_size));
00619
00620 if (space != free_space.end())
00621 {
00622 stxxl::int64 region_pos = (*space).first;
00623 stxxl::int64 region_size = (*space).second;
00624 free_space.erase(space);
00625 if (region_size > requested_size)
00626 free_space[region_pos + requested_size] = region_size - requested_size;
00627
00628 begin->offset = region_pos;
00629 for (++begin; begin != end; ++begin)
00630 {
00631 begin->offset = (begin - 1)->offset + (begin - 1)->size;
00632 }
00633 free_bytes -= requested_size;
00634
00635
00636 #ifndef STXXL_BOOST_THREADS
00637 mutex.unlock();
00638 #endif
00639
00640 return disk_bytes;
00641 }
00642
00643
00644 STXXL_VERBOSE1("Warning, when allocation an external memory space, no contiguous region found");
00645 STXXL_VERBOSE1("It might harm the performance");
00646 if (requested_size == BLK_SIZE)
00647 {
00648 assert(end - begin == 1);
00649
00650 STXXL_ERRMSG("Warning: Severe external memory space fragmentation!");
00651 dump();
00652
00653 STXXL_ERRMSG("External memory block allocation error: " << requested_size <<
00654 " bytes requested, " << free_bytes <<
00655 " bytes free. Trying to extend the external memory space...");
00656
00657 begin->offset = disk_bytes;
00658 disk_bytes += BLK_SIZE;
00659
00660 #ifndef STXXL_BOOST_THREADS
00661 mutex.unlock();
00662 #endif
00663
00664 return disk_bytes;
00665 }
00666
00667 assert(requested_size > BLK_SIZE);
00668 assert(end - begin > 1);
00669
00670 typename BIDArray<BLK_SIZE>::iterator middle = begin + ((end - begin) / 2);
00671 new_blocks(begin, middle);
00672 new_blocks(middle, end);
00673
00674 #ifndef STXXL_BOOST_THREADS
00675 mutex.unlock();
00676 #endif
00677
00678 return disk_bytes;
00679 }
00680
00681
00682 template <unsigned BLK_SIZE>
00683 void DiskAllocator::delete_block(const BID<BLK_SIZE> & bid)
00684 {
00685 #ifdef STXXL_BOOST_THREADS
00686 boost::mutex::scoped_lock lock(mutex);
00687 #else
00688 mutex.lock();
00689 #endif
00690
00691 STXXL_VERBOSE2("DiskAllocator::delete_block<BLK_SIZE>, BLK_SIZE = " << BLK_SIZE
00692 << ", free:" << free_bytes << " total:" << disk_bytes);
00693 STXXL_VERBOSE2("Deallocating a block with size: " << bid.size);
00694
00695
00696
00697 stxxl::int64 region_pos = bid.offset;
00698 stxxl::int64 region_size = bid.size;
00699 STXXL_VERBOSE2("Deallocating a block with size: " << region_size << " position: " << region_pos);
00700 if (!free_space.empty())
00701 {
00702 sortseq::iterator succ = free_space.upper_bound(region_pos);
00703 sortseq::iterator pred = succ;
00704 pred--;
00705 check_corruption(region_pos, region_size, pred, succ);
00706 if (succ == free_space.end())
00707 {
00708 if (pred == free_space.end())
00709 {
00710 STXXL_ERRMSG("Error deallocating block at " << bid.offset << " size " << bid.size);
00711 STXXL_ERRMSG(((pred == succ) ? "pred==succ" : "pred!=succ"));
00712 STXXL_ERRMSG(((pred == free_space.begin()) ? "pred==free_space.begin()" : "pred!=free_space.begin()"));
00713 STXXL_ERRMSG(((pred == free_space.end()) ? "pred==free_space.end()" : "pred!=free_space.end()"));
00714 STXXL_ERRMSG(((succ == free_space.begin()) ? "succ==free_space.begin()" : "succ!=free_space.begin()"));
00715 STXXL_ERRMSG(((succ == free_space.end()) ? "succ==free_space.end()" : "succ!=free_space.end()"));
00716 dump();
00717 assert(pred != free_space.end());
00718 }
00719 if ((*pred).first + (*pred).second == region_pos)
00720 {
00721
00722 region_size += (*pred).second;
00723 region_pos = (*pred).first;
00724 free_space.erase(pred);
00725 }
00726 }
00727 else
00728 {
00729 if (free_space.size() > 1)
00730 {
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743 bool succ_is_not_the_first = (succ != free_space.begin());
00744 if ((*succ).first == region_pos + region_size)
00745 {
00746
00747 region_size += (*succ).second;
00748 free_space.erase(succ);
00749 }
00750 if (succ_is_not_the_first)
00751 {
00752 if (pred == free_space.end())
00753 {
00754 STXXL_ERRMSG("Error deallocating block at " << bid.offset << " size " << bid.size);
00755 STXXL_ERRMSG(((pred == succ) ? "pred==succ" : "pred!=succ"));
00756 STXXL_ERRMSG(((pred == free_space.begin()) ? "pred==free_space.begin()" : "pred!=free_space.begin()"));
00757 STXXL_ERRMSG(((pred == free_space.end()) ? "pred==free_space.end()" : "pred!=free_space.end()"));
00758 STXXL_ERRMSG(((succ == free_space.begin()) ? "succ==free_space.begin()" : "succ!=free_space.begin()"));
00759 STXXL_ERRMSG(((succ == free_space.end()) ? "succ==free_space.end()" : "succ!=free_space.end()"));
00760 dump();
00761 assert(pred != free_space.end());
00762 }
00763 if ((*pred).first + (*pred).second == region_pos)
00764 {
00765
00766 region_size += (*pred).second;
00767 region_pos = (*pred).first;
00768 free_space.erase(pred);
00769 }
00770 }
00771 }
00772 else
00773 {
00774 if ((*succ).first == region_pos + region_size)
00775 {
00776
00777 region_size += (*succ).second;
00778 free_space.erase(succ);
00779 }
00780 }
00781 }
00782 }
00783
00784 free_space[region_pos] = region_size;
00785 free_bytes += stxxl::int64(bid.size);
00786
00787
00788
00789 #ifndef STXXL_BOOST_THREADS
00790 mutex.unlock();
00791 #endif
00792 }
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00842 class config : private noncopyable
00843 {
00844 struct DiskEntry
00845 {
00846 std::string path;
00847 std::string io_impl;
00848 stxxl::int64 size;
00849 };
00850 std::vector<DiskEntry> disks_props;
00851
00852
00853 unsigned first_flash;
00854
00855 config(const char * config_path = "./.stxxl");
00856
00857 public:
00860 inline unsigned disks_number() const
00861 {
00862 return disks_props.size();
00863 }
00864
00867 inline std::pair<unsigned, unsigned> regular_disk_range() const
00868 {
00869 return std::pair<unsigned, unsigned>(0, first_flash);
00870 }
00871
00874 inline std::pair<unsigned, unsigned> flash_range() const
00875 {
00876 return std::pair<unsigned, unsigned>(first_flash, disks_props.size());
00877 }
00878
00882 inline const std::string & disk_path(int disk) const
00883 {
00884 return disks_props[disk].path;
00885 }
00889 inline stxxl::int64 disk_size(int disk) const
00890 {
00891 return disks_props[disk].size;
00892 }
00895 inline const std::string & disk_io_impl(int disk) const
00896 {
00897 return disks_props[disk].io_impl;
00898 }
00899
00902 static config * get_instance();
00903
00904 private:
00905 static config * instance;
00906 };
00907
00908
00909 class FileCreator
00910 {
00911 public:
00912 virtual stxxl::file * create(const std::string & io_impl,
00913 const std::string & filename,
00914 int options, int disk)
00915 {
00916 if (io_impl == "syscall")
00917 {
00918 stxxl::ufs_file_base * result = new stxxl::syscall_file(filename,
00919 options,
00920 disk);
00921 result->lock();
00922 return result;
00923 }
00924 #ifndef BOOST_MSVC
00925 else if (io_impl == "mmap")
00926 {
00927 stxxl::ufs_file_base * result = new stxxl::mmap_file(filename,
00928 options, disk);
00929 result->lock();
00930 return result;
00931 }
00932 else if (io_impl == "simdisk")
00933 {
00934 stxxl::ufs_file_base * result = new stxxl::sim_disk_file(filename,
00935 options,
00936 disk);
00937 result->lock();
00938 return result;
00939 }
00940 #else
00941 else if (io_impl == "wincall")
00942 {
00943 stxxl::wfs_file_base * result = new stxxl::wincall_file(filename,
00944 options, disk);
00945 result->lock();
00946 return result;
00947 }
00948 #endif
00949 #ifdef STXXL_BOOST_CONFIG
00950 else if (io_impl == "boostfd")
00951 return new stxxl::boostfd_file(filename,
00952 options, disk);
00953 #endif
00954
00955 STXXL_THROW(std::runtime_error, "FileCreator::create", "Unsupported disk I/O implementation " <<
00956 io_impl << " .");
00957
00958 return NULL;
00959 }
00960
00961 virtual ~FileCreator() { }
00962 };
00963
00967
00970 struct basic_allocation_strategy
00971 {
00972 basic_allocation_strategy(int disks_begin, int disks_end);
00973 basic_allocation_strategy();
00974 int operator () (int i) const;
00975 static const char * name();
00976 };
00977
00980 struct striping
00981 {
00982 int begin, diff;
00983 striping(int b, int e) : begin(b), diff(e - b)
00984 { }
00985 striping() : begin(0)
00986 {
00987 diff = config::get_instance()->disks_number();
00988 }
00989 int operator () (int i) const
00990 {
00991 return begin + i % diff;
00992 }
00993 static const char * name()
00994 {
00995 return "striping";
00996 }
00997
00998 virtual ~striping()
00999 { }
01000 };
01001
01004 struct FR : public striping
01005 {
01006 random_number<random_uniform_fast> rnd;
01007 FR(int b, int e) : striping(b, e)
01008 { }
01009 FR() : striping()
01010 { }
01011 int operator () (int ) const
01012 {
01013 return begin + rnd(diff);
01014 }
01015 static const char * name()
01016 {
01017 return "fully randomized striping";
01018 }
01019 };
01020
01023 struct SR : public striping
01024 {
01025 random_number<random_uniform_fast> rnd;
01026 int offset;
01027 SR(int b, int e) : striping(b, e)
01028 {
01029 offset = rnd(diff);
01030 }
01031 SR() : striping()
01032 {
01033 offset = rnd(diff);
01034 }
01035 int operator () (int i) const
01036 {
01037 return begin + (i + offset) % diff;
01038 }
01039 static const char * name()
01040 {
01041 return "simple randomized striping";
01042 }
01043 };
01044
01047 struct RC : public striping
01048 {
01049 std::vector<int> perm;
01050
01051 RC(int b, int e) : striping(b, e), perm(diff)
01052 {
01053 for (int i = 0; i < diff; i++)
01054 perm[i] = i;
01055
01056 stxxl::random_number<random_uniform_fast> rnd;
01057 std::random_shuffle(perm.begin(), perm.end(), rnd __STXXL_FORCE_SEQUENTIAL);
01058 }
01059 RC() : striping(), perm(diff)
01060 {
01061 for (int i = 0; i < diff; i++)
01062 perm[i] = i;
01063
01064 random_number<random_uniform_fast> rnd;
01065 std::random_shuffle(perm.begin(), perm.end(), rnd __STXXL_FORCE_SEQUENTIAL);
01066 }
01067 int operator () (int i) const
01068 {
01069 return begin + perm[i % diff];
01070 }
01071 static const char * name()
01072 {
01073 return "randomized cycling striping";
01074 }
01075 };
01076
01077 struct RC_disk : public RC
01078 {
01079 RC_disk(int b, int e) : RC(b, e)
01080 { }
01081 RC_disk() : RC(config::get_instance()->regular_disk_range().first, config::get_instance()->regular_disk_range().second)
01082 { }
01083 static const char * name()
01084 {
01085 return "Randomized cycling striping on regular disks";
01086 }
01087 };
01088
01089 struct RC_flash : public RC
01090 {
01091 RC_flash(int b, int e) : RC(b, e)
01092 { }
01093 RC_flash() : RC(config::get_instance()->flash_range().first, config::get_instance()->flash_range().second)
01094 { }
01095 static const char * name()
01096 {
01097 return "Randomized cycling striping on flash devices";
01098 }
01099 };
01100
01103 struct single_disk
01104 {
01105 const int disk;
01106 single_disk(int d, int = 0) : disk(d)
01107 { }
01108
01109 single_disk() : disk(0)
01110 { }
01111 int operator () (int ) const
01112 {
01113 return disk;
01114 }
01115 static const char * name()
01116 {
01117 return "single disk";
01118 }
01119 };
01120
01122
01124 template <class BaseAllocator_>
01125 struct offset_allocator
01126 {
01127 BaseAllocator_ base;
01128 int_type offset;
01132 offset_allocator(int_type offset_) : base(), offset(offset_) { }
01137 offset_allocator(int_type offset_, BaseAllocator_ & base_) : base(base_), offset(offset_) { }
01138 int operator () (int_type i) const
01139 {
01140 return base(offset + i);
01141 }
01142 };
01143
01145
01146
01147
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01197
01200 class block_manager : private noncopyable
01201 {
01202 DiskAllocator ** disk_allocators;
01203 file ** disk_files;
01204
01205 unsigned ndisks;
01206 block_manager();
01207
01208 protected:
01209 template <class BIDType, class DiskAssgnFunctor, class BIDIteratorClass>
01210 void new_blocks_int(
01211 const unsigned_type nblocks,
01212 DiskAssgnFunctor functor,
01213 BIDIteratorClass out);
01214
01215 public:
01218 static block_manager * get_instance();
01219
01221
01228 template <class DiskAssgnFunctor, class BIDIteratorClass>
01229 void new_blocks(
01230 DiskAssgnFunctor functor,
01231 BIDIteratorClass bidbegin,
01232 BIDIteratorClass bidend);
01233
01242 template <class BlockType, class DiskAssgnFunctor, class BIDIteratorClass>
01243 void new_blocks(
01244 const unsigned_type nblocks,
01245 DiskAssgnFunctor functor,
01246 BIDIteratorClass out);
01247
01248
01250
01254 template <class BIDIteratorClass>
01255 void delete_blocks(const BIDIteratorClass & bidbegin, const BIDIteratorClass & bidend);
01256
01259 template <unsigned BLK_SIZE>
01260 void delete_block(const BID<BLK_SIZE> & bid);
01261
01262 ~block_manager();
01263
01264 private:
01265 static block_manager * instance;
01266 };
01267
01268
01269 template <class BIDType, class DiskAssgnFunctor, class OutputIterator>
01270 void block_manager::new_blocks_int(
01271 const unsigned_type nblocks,
01272 DiskAssgnFunctor functor,
01273 OutputIterator out)
01274 {
01275 typedef BIDType bid_type;
01276 typedef BIDArray<bid_type::t_size> bid_array_type;
01277
01278
01279 int_type * bl = new int_type[ndisks];
01280 bid_array_type * disk_bids = new bid_array_type[ndisks];
01281 file ** disk_ptrs = new file *[nblocks];
01282
01283 memset(bl, 0, ndisks * sizeof(int_type));
01284
01285 unsigned_type i = 0;
01286
01287 for ( ; i < nblocks; ++i )
01288 {
01289 const int disk = functor(i);
01290 disk_ptrs[i] = disk_files[disk];
01291
01292 bl[disk]++;
01293 }
01294
01295 for (i = 0; i < ndisks; ++i)
01296 {
01297 if (bl[i])
01298 {
01299 disk_bids[i].resize(bl[i]);
01300 const stxxl::int64 old_capacity =
01301 disk_allocators[i]->get_total_bytes();
01302 const stxxl::int64 new_capacity =
01303 disk_allocators[i]->new_blocks(disk_bids[i]);
01304 if (old_capacity != new_capacity)
01305 {
01306
01307 disk_files[i]->set_size(new_capacity);
01308 }
01309 }
01310 }
01311
01312 memset(bl, 0, ndisks * sizeof(int_type));
01313
01314 OutputIterator it = out;
01315 for (i = 0 ; i != nblocks; ++it, ++i)
01316 {
01317
01318
01319 const int disk = disk_ptrs[i]->get_disk_number();
01320 *it = bid_type(disk_ptrs[i], disk_bids[disk][bl[disk]++].offset);
01321 }
01322
01323 delete[] bl;
01324 delete[] disk_bids;
01325 delete[] disk_ptrs;
01326 }
01327
01328 template <class BlockType, class DiskAssgnFunctor, class OutputIterator>
01329 void block_manager::new_blocks(
01330 const unsigned_type nblocks,
01331 DiskAssgnFunctor functor,
01332 OutputIterator out)
01333 {
01334 typedef typename BlockType::bid_type bid_type;
01335 new_blocks_int<bid_type>(nblocks, functor, out);
01336 }
01337
01338 template <class DiskAssgnFunctor, class BIDIteratorClass>
01339 void block_manager::new_blocks(
01340 DiskAssgnFunctor functor,
01341 BIDIteratorClass bidbegin,
01342 BIDIteratorClass bidend)
01343 {
01344 typedef typename std::iterator_traits<BIDIteratorClass>::value_type bid_type;
01345
01346 unsigned_type nblocks = 0;
01347
01348 BIDIteratorClass bidbegin_copy(bidbegin);
01349 while (bidbegin_copy != bidend)
01350 {
01351 ++bidbegin_copy;
01352 ++nblocks;
01353 }
01354
01355 new_blocks_int<bid_type>(nblocks, functor, bidbegin);
01356 }
01357
01358
01359 template <unsigned BLK_SIZE>
01360 void block_manager::delete_block(const BID<BLK_SIZE> & bid)
01361 {
01362
01363
01364 if (bid.storage->get_disk_number() == -1)
01365 return;
01366 assert(bid.storage->get_disk_number() >= 0);
01367 disk_allocators[bid.storage->get_disk_number()]->delete_block(bid);
01368 }
01369
01370
01371 template <class BIDIteratorClass>
01372 void block_manager::delete_blocks(
01373 const BIDIteratorClass & bidbegin,
01374 const BIDIteratorClass & bidend)
01375 {
01376 for (BIDIteratorClass it = bidbegin; it != bidend; it++)
01377 {
01378 delete_block(*it);
01379 }
01380 }
01381
01382 #ifndef STXXL_DEFAULT_ALLOC_STRATEGY
01383 #define STXXL_DEFAULT_ALLOC_STRATEGY stxxl::RC
01384 #endif
01385
01386
01387 #ifndef STXXL_DEFAULT_BLOCK_SIZE
01388 #define STXXL_DEFAULT_BLOCK_SIZE(type) (2 * 1024 * 1024) // use traits
01389 #endif
01390
01392
01393 __STXXL_END_NAMESPACE
01394
01395
01396 #endif // !STXXL_MNG_HEADER
01397