00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #ifndef STXXL_PREFETCH_POOL_HEADER
00015 #define STXXL_PREFETCH_POOL_HEADER
00016
00017 #include <list>
00018
00019 #ifdef STXXL_BOOST_CONFIG
00020 #include <boost/config.hpp>
00021 #endif
00022
00023 #include <stxxl/bits/mng/write_pool.h>
00024 #include <stxxl/bits/compat_hash_map.h>
00025
00026
00027 __STXXL_BEGIN_NAMESPACE
00028
00031
00033 template <class BlockType>
00034 class prefetch_pool : private noncopyable
00035 {
00036 public:
00037 typedef BlockType block_type;
00038 typedef typename block_type::bid_type bid_type;
00039
00040 protected:
00041 struct bid_hash
00042 {
00043 size_t operator () (const bid_type & bid) const
00044 {
00045 size_t result = size_t(bid.storage) +
00046 size_t(bid.offset & 0xffffffff) + size_t(bid.offset >> 32);
00047 return result;
00048 }
00049 #ifdef BOOST_MSVC
00050 bool operator () (const bid_type & a, const bid_type & b) const
00051 {
00052 return (a.storage < b.storage) || (a.storage == b.storage && a.offset < b.offset);
00053 }
00054 enum
00055 {
00056 bucket_size = 4,
00057 min_buckets = 8
00058 };
00059 #endif
00060 };
00061 typedef std::pair<block_type *, request_ptr> busy_entry;
00062 typedef typename compat_hash_map<bid_type, busy_entry, bid_hash>::result hash_map_type;
00063 typedef typename std::list<block_type *>::iterator free_blocks_iterator;
00064 typedef typename hash_map_type::iterator busy_blocks_iterator;
00065
00066
00067 std::list<block_type *> free_blocks;
00068
00069 hash_map_type busy_blocks;
00070
00071 unsigned_type free_blocks_size;
00072
00073 public:
00076 explicit prefetch_pool(unsigned_type init_size = 1) : free_blocks_size(init_size)
00077 {
00078 unsigned_type i = 0;
00079 for ( ; i < init_size; ++i)
00080 free_blocks.push_back(new block_type);
00081 }
00082
00083 void swap(prefetch_pool & obj)
00084 {
00085 std::swap(free_blocks, obj.free_blocks);
00086 std::swap(busy_blocks, obj.busy_blocks);
00087 std::swap(free_blocks_size, obj.free_blocks_size);
00088 }
00089
00091 virtual ~prefetch_pool()
00092 {
00093 while (!free_blocks.empty())
00094 {
00095 delete free_blocks.back();
00096 free_blocks.pop_back();
00097 }
00098
00099 try
00100 {
00101 busy_blocks_iterator i2 = busy_blocks.begin();
00102 for ( ; i2 != busy_blocks.end(); ++i2)
00103 {
00104 i2->second.second->wait();
00105 delete i2->second.first;
00106 }
00107 }
00108 catch (...)
00109 { }
00110 }
00112 unsigned_type size() const { return free_blocks_size + busy_blocks.size(); }
00113
00121 bool hint(bid_type bid)
00122 {
00123
00124 if (in_prefetching(bid)) {
00125 STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " was already cached");
00126 return true;
00127 }
00128
00129 if (free_blocks_size)
00130 {
00131 --free_blocks_size;
00132 block_type * block = free_blocks.back();
00133 free_blocks.pop_back();
00134 STXXL_VERBOSE2("prefetch_pool::hint bid=" << bid << " => prefetching");
00135 request_ptr req = block->read(bid);
00136 busy_blocks[bid] = busy_entry(block, req);
00137 return true;
00138 }
00139 STXXL_VERBOSE2("prefetch_pool::hint bid=" << bid << " => no free blocks for prefetching");
00140 return false;
00141 }
00142
00143 bool hint(bid_type bid, write_pool<block_type> & w_pool)
00144 {
00145
00146 if (in_prefetching(bid)) {
00147 STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " was already cached");
00148 return true;
00149 }
00150
00151 if (free_blocks_size)
00152 {
00153 --free_blocks_size;
00154 block_type * block = free_blocks.back();
00155 free_blocks.pop_back();
00156 if (w_pool.has_request(bid))
00157 {
00158 busy_entry wp_request = w_pool.steal_request(bid);
00159 STXXL_VERBOSE1("prefetch_pool::hint2 bid=" << bid << " was in write cache at " << wp_request.first);
00160 assert(wp_request.first != 0);
00161 w_pool.add(block);
00162 busy_blocks[bid] = wp_request;
00163 return true;
00164 }
00165 STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " => prefetching");
00166 request_ptr req = block->read(bid);
00167 busy_blocks[bid] = busy_entry(block, req);
00168 return true;
00169 }
00170 STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " => no free blocks for prefetching");
00171 return false;
00172 }
00173
00174 bool invalidate(bid_type bid)
00175 {
00176 busy_blocks_iterator cache_el = busy_blocks.find(bid);
00177 if (cache_el == busy_blocks.end())
00178 return false;
00179
00180
00181
00182 if (cache_el->second.second->get_type() == request::READ)
00183 cache_el->second.second->cancel();
00184
00185 cache_el->second.second->wait();
00186 ++free_blocks_size;
00187 free_blocks.push_back(cache_el->second.first);
00188 busy_blocks.erase(cache_el);
00189 return true;
00190 }
00191
00192 bool in_prefetching(bid_type bid)
00193 {
00194 return (busy_blocks.find(bid) != busy_blocks.end());
00195 }
00196
00203 request_ptr read(block_type * & block, bid_type bid)
00204 {
00205 busy_blocks_iterator cache_el = busy_blocks.find(bid);
00206 if (cache_el == busy_blocks.end())
00207 {
00208
00209 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => no copy in cache, retrieving to " << block);
00210 return block->read(bid);
00211 }
00212
00213
00214 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => copy in cache exists");
00215 ++free_blocks_size;
00216 free_blocks.push_back(block);
00217 block = cache_el->second.first;
00218 request_ptr result = cache_el->second.second;
00219 busy_blocks.erase(cache_el);
00220 return result;
00221 }
00222
00223 request_ptr read(block_type * & block, bid_type bid, write_pool<block_type> & w_pool)
00224 {
00225
00226 busy_blocks_iterator cache_el = busy_blocks.find(bid);
00227 if (cache_el != busy_blocks.end())
00228 {
00229
00230 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => copy in cache exists");
00231 ++free_blocks_size;
00232 free_blocks.push_back(block);
00233 block = cache_el->second.first;
00234 request_ptr result = cache_el->second.second;
00235 busy_blocks.erase(cache_el);
00236 return result;
00237 }
00238
00239
00240 if (w_pool.has_request(bid))
00241 {
00242 busy_entry wp_request = w_pool.steal_request(bid);
00243 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " was in write cache at " << wp_request.first);
00244 assert(wp_request.first != 0);
00245 w_pool.add(block);
00246 block = wp_request.first;
00247 return wp_request.second;
00248 }
00249
00250
00251 STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => no copy in cache, retrieving to " << block);
00252 return block->read(bid);
00253 }
00254
00261 unsigned_type resize(unsigned_type new_size)
00262 {
00263 int_type diff = int_type(new_size) - int_type(size());
00264 if (diff > 0)
00265 {
00266 free_blocks_size += diff;
00267 while (--diff >= 0)
00268 free_blocks.push_back(new block_type);
00269
00270
00271 return size();
00272 }
00273
00274 while (diff < 0 && free_blocks_size > 0)
00275 {
00276 ++diff;
00277 --free_blocks_size;
00278 delete free_blocks.back();
00279 free_blocks.pop_back();
00280 }
00281 return size();
00282 }
00283 };
00284
00286
00287 __STXXL_END_NAMESPACE
00288
00289 namespace std
00290 {
00291 template <class BlockType>
00292 void swap(stxxl::prefetch_pool<BlockType> & a,
00293 stxxl::prefetch_pool<BlockType> & b)
00294 {
00295 a.swap(b);
00296 }
00297 }
00298
00299 #endif // !STXXL_PREFETCH_POOL_HEADER
00300