Stxxl
1.4.0
|
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