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