Stxxl  1.4.0
include/stxxl/bits/mng/prefetch_pool.h
Go to the documentation of this file.
00001 /***************************************************************************
00002  *  include/stxxl/bits/mng/prefetch_pool.h
00003  *
00004  *  Part of the STXXL. See http://stxxl.sourceforge.net
00005  *
00006  *  Copyright (C) 2003-2004 Roman Dementiev <dementiev@mpi-sb.mpg.de>
00007  *  Copyright (C) 2009 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
00008  *
00009  *  Distributed under the Boost Software License, Version 1.0.
00010  *  (See accompanying file LICENSE_1_0.txt or copy at
00011  *  http://www.boost.org/LICENSE_1_0.txt)
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 
00029 //! \addtogroup schedlayer
00030 //! \{
00031 
00032 //! \brief Implements dynamically resizable prefetching pool
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         {                               // parameters for hash table
00056             bucket_size = 4,            // 0 < bucket_size
00057             min_buckets = 8             // min_buckets = 2 ^^ N, 0 < N
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     // contains free prefetch blocks
00067     std::list<block_type *> free_blocks;
00068     // blocks that are in reading or already read but not retrieved by user
00069     hash_map_type busy_blocks;
00070 
00071     unsigned_type free_blocks_size;
00072 
00073 public:
00074     //! \brief Constructs pool
00075     //! \param init_size initial number of blocks in the pool
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 
00090     //! \brief Waits for completion of all ongoing read requests and frees memory
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     }
00111     //! \brief Returns number of owned blocks
00112     unsigned_type size() const { return free_blocks_size + busy_blocks.size(); }
00113 
00114     //! \brief Gives a hint for prefetching a block
00115     //! \param bid address of a block to be prefetched
00116     //! \return \c true if there was a free block to do prefetch and prefetching
00117     //! was scheduled, \c false otherwise
00118     //! \note If there are no free blocks available (all blocks
00119     //! are already in reading or read but not retrieved by user calling \c read
00120     //! method) calling \c hint function has no effect
00121     bool hint(bid_type bid)
00122     {
00123         // if block is already hinted, no need to hint it again
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) //  only if we have a free block
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         // if block is already hinted, no need to hint it again
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) //  only if we have a free block
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);  //in exchange
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         // cancel request if it is a read request, there might be
00181         // write requests 'stolen' from a write_pool that may not be canceled
00182         if (cache_el->second.second->get_type() == request::READ)
00183             cache_el->second.second->cancel();
00184         // finish the request
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 
00197     //! \brief Reads block. If this block is cached block is not read but passed from the cache
00198     //! \param block block object, where data to be read to. If block was cached \c block 's
00199     //! ownership goes to the pool and block from cache is returned in \c block value.
00200     //! \param bid address of the block
00201     //! \warning \c block parameter must be allocated dynamically using \c new .
00202     //! \return request pointer object of read operation
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             // not cached
00209             STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => no copy in cache, retrieving to " << block);
00210             return block->read(bid);
00211         }
00212 
00213         // cached
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         // try cache
00226         busy_blocks_iterator cache_el = busy_blocks.find(bid);
00227         if (cache_el != busy_blocks.end())
00228         {
00229             // cached
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         // try w_pool cache
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);  //in exchange
00246             block = wp_request.first;
00247             return wp_request.second;
00248         }
00249 
00250         // not cached
00251         STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => no copy in cache, retrieving to " << block);
00252         return block->read(bid);
00253     }
00254 
00255     //! \brief Resizes size of the pool
00256     //! \param new_size desired size of the pool. If some
00257     //! blocks are used for prefetching, these blocks can't be freed.
00258     //! Only free blocks (not in prefetching) can be freed by reducing
00259     //! the size of the pool calling this method.
00260     //! \return new size of the pool
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 
00285 //! \}
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 // vim: et:ts=4:sw=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines