Stxxl  1.4.0
include/stxxl/bits/mng/write_pool.h
Go to the documentation of this file.
00001 /***************************************************************************
00002  *  include/stxxl/bits/mng/write_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_WRITE_POOL_HEADER
00015 #define STXXL_WRITE_POOL_HEADER
00016 
00017 #include <list>
00018 
00019 #ifdef STXXL_BOOST_CONFIG
00020  #include <boost/config.hpp>
00021 #endif
00022 
00023 #include <stxxl/bits/noncopyable.h>
00024 #include <stxxl/bits/deprecated.h>
00025 #include <stxxl/bits/io/request_operations.h>
00026 
00027 #define STXXL_VERBOSE_WPOOL(msg) STXXL_VERBOSE1("write_pool[" << static_cast<void *>(this) << "]" << msg)
00028 
00029 
00030 __STXXL_BEGIN_NAMESPACE
00031 
00032 //! \addtogroup schedlayer
00033 //! \{
00034 
00035 
00036 //! \brief Implements dynamically resizable buffered writing pool
00037 template <class BlockType>
00038 class write_pool : private noncopyable
00039 {
00040 public:
00041     typedef BlockType block_type;
00042     typedef typename block_type::bid_type bid_type;
00043 
00044     // a hack to make wait_any work with busy_entry type
00045     struct busy_entry
00046     {
00047         block_type * block;
00048         request_ptr req;
00049         bid_type bid;
00050 
00051         busy_entry() : block(NULL) { }
00052         busy_entry(const busy_entry & a) : block(a.block), req(a.req), bid(a.bid) { }
00053         busy_entry(block_type * & bl, request_ptr & r, bid_type & bi) :
00054             block(bl), req(r), bid(bi) { }
00055 
00056         operator request_ptr () { return req; }
00057     };
00058     typedef typename std::list<block_type *>::iterator free_blocks_iterator;
00059     typedef typename std::list<busy_entry>::iterator busy_blocks_iterator;
00060 
00061 protected:
00062     // contains free write blocks
00063     std::list<block_type *> free_blocks;
00064     // blocks that are in writing
00065     std::list<busy_entry> busy_blocks;
00066 
00067 public:
00068     //! \brief Constructs pool
00069     //! \param init_size initial number of blocks in the pool
00070     explicit write_pool(unsigned_type init_size = 1)
00071     {
00072         for (unsigned_type i = 0; i < init_size; ++i)
00073         {
00074             free_blocks.push_back(new block_type);
00075             STXXL_VERBOSE_WPOOL("  create block=" << free_blocks.back());
00076         }
00077     }
00078 
00079     void swap(write_pool & obj)
00080     {
00081         std::swap(free_blocks, obj.free_blocks);
00082         std::swap(busy_blocks, obj.busy_blocks);
00083     }
00084 
00085     //! \brief Waits for completion of all ongoing write requests and frees memory
00086     virtual ~write_pool()
00087     {
00088         STXXL_VERBOSE_WPOOL("::~write_pool free_blocks.size()=" << free_blocks.size() <<
00089                             " busy_blocks.size()=" << busy_blocks.size());
00090         while (!free_blocks.empty())
00091         {
00092             STXXL_VERBOSE_WPOOL("  delete free block=" << free_blocks.back());
00093             delete free_blocks.back();
00094             free_blocks.pop_back();
00095         }
00096 
00097         try
00098         {
00099             for (busy_blocks_iterator i2 = busy_blocks.begin(); i2 != busy_blocks.end(); ++i2)
00100             {
00101                 i2->req->wait();
00102                 STXXL_VERBOSE_WPOOL("  delete busy block=" << free_blocks.back());
00103                 delete i2->block;
00104             }
00105         }
00106         catch (...)
00107         { }
00108     }
00109 
00110     //! \brief Returns number of owned blocks
00111     unsigned_type size() const { return free_blocks.size() + busy_blocks.size(); }
00112 
00113     //! \brief Passes a block to the pool for writing
00114     //! \param block block to write. Ownership of the block goes to the pool.
00115     //! \c block must be allocated dynamically with using \c new .
00116     //! \param bid location, where to write
00117     //! \warning \c block must be allocated dynamically with using \c new .
00118     //! \return request object of the write operation
00119     request_ptr write(block_type * & block, bid_type bid)
00120     {
00121         STXXL_VERBOSE_WPOOL("::write: " << block << " @ " << bid);
00122         for (busy_blocks_iterator i2 = busy_blocks.begin(); i2 != busy_blocks.end(); ++i2)
00123         {
00124             if (i2->bid == bid) {
00125                 assert(i2->block != block);
00126                 STXXL_VERBOSE_WPOOL("WAW dependency");
00127                 // try to cancel the obsolete request
00128                 i2->req->cancel();
00129                 // invalidate the bid of the stale write request,
00130                 // prevents prefetch_pool from stealing a stale block
00131                 i2->bid.storage = 0;
00132             }
00133         }
00134         request_ptr result = block->write(bid);
00135         busy_blocks.push_back(busy_entry(block, result, bid));
00136         block = NULL; // prevent caller from using the block any further
00137         return result;
00138     }
00139 
00140     //! \brief Take out a block from the pool
00141     //! \return pointer to the block. Ownership of the block goes to the caller.
00142     block_type * steal()
00143     {
00144         assert(size() > 0);
00145         if (!free_blocks.empty())
00146         {
00147             block_type * p = free_blocks.back();
00148             STXXL_VERBOSE_WPOOL("::steal : " << free_blocks.size() << " free blocks available, serve block=" << p);
00149             free_blocks.pop_back();
00150             return p;
00151         }
00152         STXXL_VERBOSE_WPOOL("::steal : all " << busy_blocks.size() << " are busy");
00153         busy_blocks_iterator completed = wait_any(busy_blocks.begin(), busy_blocks.end());
00154         assert(completed != busy_blocks.end()); // we got something reasonable from wait_any
00155         assert(completed->req->poll());         // and it is *really* completed
00156         block_type * p = completed->block;
00157         busy_blocks.erase(completed);
00158         check_all_busy();                       // for debug
00159         STXXL_VERBOSE_WPOOL("  serve block=" << p);
00160         return p;
00161     }
00162 
00163     // deprecated name for the steal()
00164     _STXXL_DEPRECATED(block_type * get())
00165     {
00166         return steal();
00167     }
00168 
00169     //! \brief Resizes size of the pool
00170     //! \param new_size new size of the pool after the call
00171     void resize(unsigned_type new_size)
00172     {
00173         int_type diff = int_type(new_size) - int_type(size());
00174         if (diff > 0)
00175         {
00176             while (--diff >= 0)
00177             {
00178                 free_blocks.push_back(new block_type);
00179                 STXXL_VERBOSE_WPOOL("  create block=" << free_blocks.back());
00180             }
00181 
00182             return;
00183         }
00184 
00185         while (++diff <= 0)
00186             delete steal();
00187     }
00188 
00189     _STXXL_DEPRECATED(request_ptr get_request(bid_type bid))
00190     {
00191         busy_blocks_iterator i2 = busy_blocks.begin();
00192         for ( ; i2 != busy_blocks.end(); ++i2)
00193         {
00194             if (i2->bid == bid)
00195                 return i2->req;
00196         }
00197         return request_ptr();
00198     }
00199 
00200     bool has_request(bid_type bid)
00201     {
00202         for (busy_blocks_iterator i2 = busy_blocks.begin(); i2 != busy_blocks.end(); ++i2)
00203         {
00204             if (i2->bid == bid)
00205                 return true;
00206         }
00207         return false;
00208     }
00209 
00210     _STXXL_DEPRECATED(block_type * steal(bid_type bid))
00211     {
00212         busy_blocks_iterator i2 = busy_blocks.begin();
00213         for ( ; i2 != busy_blocks.end(); ++i2)
00214         {
00215             if (i2->bid == bid)
00216             {
00217                 block_type * p = i2->block;
00218                 i2->req->wait();
00219                 busy_blocks.erase(i2);
00220                 return p;
00221             }
00222         }
00223         return NULL;
00224     }
00225 
00226     // returns a block and a (potentially unfinished) I/O request associated with it
00227     std::pair<block_type *, request_ptr> steal_request(bid_type bid)
00228     {
00229         for (busy_blocks_iterator i2 = busy_blocks.begin(); i2 != busy_blocks.end(); ++i2)
00230         {
00231             if (i2->bid == bid)
00232             {
00233                 // remove busy block from list, request has not yet been waited for!
00234                 block_type * blk = i2->block;
00235                 request_ptr req = i2->req;
00236                 busy_blocks.erase(i2);
00237 
00238                 STXXL_VERBOSE_WPOOL("::steal_request block=" << blk);
00239                 // hand over block and (unfinished) request to caller
00240                 return std::pair<block_type *, request_ptr>(blk, req);
00241             }
00242         }
00243         STXXL_VERBOSE_WPOOL("::steal_request NOT FOUND");
00244         // not matching request found, return a dummy
00245         return std::pair<block_type *, request_ptr>((block_type *)NULL, request_ptr());
00246     }
00247 
00248     void add(block_type * & block)
00249     {
00250         STXXL_VERBOSE_WPOOL("::add " << block);
00251         free_blocks.push_back(block);
00252         block = NULL; // prevent caller from using the block any further
00253     }
00254 
00255 protected:
00256     void check_all_busy()
00257     {
00258         busy_blocks_iterator cur = busy_blocks.begin();
00259         int_type cnt = 0;
00260         while (cur != busy_blocks.end())
00261         {
00262             if (cur->req->poll())
00263             {
00264                 free_blocks.push_back(cur->block);
00265                 cur = busy_blocks.erase(cur);
00266                 ++cnt;
00267                 continue;
00268             }
00269             ++cur;
00270         }
00271         STXXL_VERBOSE_WPOOL("::check_all_busy : " << cnt <<
00272                        " are completed out of " << busy_blocks.size() + cnt << " busy blocks");
00273     }
00274 };
00275 
00276 //! \}
00277 
00278 __STXXL_END_NAMESPACE
00279 
00280 
00281 namespace std
00282 {
00283     template <class BlockType>
00284     void swap(stxxl::write_pool<BlockType> & a,
00285               stxxl::write_pool<BlockType> & b)
00286     {
00287         a.swap(b);
00288     }
00289 }
00290 
00291 #endif // !STXXL_WRITE_POOL_HEADER
00292 // vim: et:ts=4:sw=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines