00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
00064 void add_free_region(stxxl::int64 block_pos, stxxl::int64 block_size);
00065
00066
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
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
00202
00203 return;
00204 }
00205
00206
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
00221
00222 __STXXL_END_NAMESPACE
00223
00224 #endif // !STXXL_DISKALLOCATOR_HEADER
00225