Stxxl  1.3.2
prefetch_pool.h
1 /***************************************************************************
2  * include/stxxl/bits/mng/prefetch_pool.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2003-2004 Roman Dementiev <[email protected]>
7  * Copyright (C) 2009 Andreas Beckmann <[email protected]>
8  *
9  * Distributed under the Boost Software License, Version 1.0.
10  * (See accompanying file LICENSE_1_0.txt or copy at
11  * http://www.boost.org/LICENSE_1_0.txt)
12  **************************************************************************/
13 
14 #ifndef STXXL_PREFETCH_POOL_HEADER
15 #define STXXL_PREFETCH_POOL_HEADER
16 
17 #include <list>
18 
19 #ifdef STXXL_BOOST_CONFIG
20  #include <boost/config.hpp>
21 #endif
22 
23 #include <stxxl/bits/mng/write_pool.h>
24 #include <stxxl/bits/compat_hash_map.h>
25 
26 
27 __STXXL_BEGIN_NAMESPACE
28 
31 
33 template <class BlockType>
34 class prefetch_pool : private noncopyable
35 {
36 public:
37  typedef BlockType block_type;
38  typedef typename block_type::bid_type bid_type;
39 
40 protected:
41  struct bid_hash
42  {
43  size_t operator () (const bid_type & bid) const
44  {
45  size_t result = size_t(bid.storage) +
46  size_t(bid.offset & 0xffffffff) + size_t(bid.offset >> 32);
47  return result;
48  }
49 #ifdef BOOST_MSVC
50  bool operator () (const bid_type & a, const bid_type & b) const
51  {
52  return (a.storage < b.storage) || (a.storage == b.storage && a.offset < b.offset);
53  }
54  enum
55  { // parameters for hash table
56  bucket_size = 4, // 0 < bucket_size
57  min_buckets = 8 // min_buckets = 2 ^^ N, 0 < N
58  };
59 #endif
60  };
61  typedef std::pair<block_type *, request_ptr> busy_entry;
62  typedef typename compat_hash_map<bid_type, busy_entry, bid_hash>::result hash_map_type;
63  typedef typename std::list<block_type *>::iterator free_blocks_iterator;
64  typedef typename hash_map_type::iterator busy_blocks_iterator;
65 
66  // contains free prefetch blocks
67  std::list<block_type *> free_blocks;
68  // blocks that are in reading or already read but not retrieved by user
69  hash_map_type busy_blocks;
70 
71  unsigned_type free_blocks_size;
72 
73 public:
76  explicit prefetch_pool(unsigned_type init_size = 1) : free_blocks_size(init_size)
77  {
78  unsigned_type i = 0;
79  for ( ; i < init_size; ++i)
80  free_blocks.push_back(new block_type);
81  }
82 
83  void swap(prefetch_pool & obj)
84  {
85  std::swap(free_blocks, obj.free_blocks);
86  std::swap(busy_blocks, obj.busy_blocks);
87  std::swap(free_blocks_size, obj.free_blocks_size);
88  }
89 
91  virtual ~prefetch_pool()
92  {
93  while (!free_blocks.empty())
94  {
95  delete free_blocks.back();
96  free_blocks.pop_back();
97  }
98 
99  try
100  {
101  busy_blocks_iterator i2 = busy_blocks.begin();
102  for ( ; i2 != busy_blocks.end(); ++i2)
103  {
104  i2->second.second->wait();
105  delete i2->second.first;
106  }
107  }
108  catch (...)
109  { }
110  }
112  unsigned_type size() const { return free_blocks_size + busy_blocks.size(); }
113 
121  bool hint(bid_type bid)
122  {
123  // if block is already hinted, no need to hint it again
124  if (in_prefetching(bid)) {
125  STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " was already cached");
126  return true;
127  }
128 
129  if (free_blocks_size) // only if we have a free block
130  {
131  --free_blocks_size;
132  block_type * block = free_blocks.back();
133  free_blocks.pop_back();
134  STXXL_VERBOSE2("prefetch_pool::hint bid=" << bid << " => prefetching");
135  request_ptr req = block->read(bid);
136  busy_blocks[bid] = busy_entry(block, req);
137  return true;
138  }
139  STXXL_VERBOSE2("prefetch_pool::hint bid=" << bid << " => no free blocks for prefetching");
140  return false;
141  }
142 
143  bool hint(bid_type bid, write_pool<block_type> & w_pool)
144  {
145  // if block is already hinted, no need to hint it again
146  if (in_prefetching(bid)) {
147  STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " was already cached");
148  return true;
149  }
150 
151  if (free_blocks_size) // only if we have a free block
152  {
153  --free_blocks_size;
154  block_type * block = free_blocks.back();
155  free_blocks.pop_back();
156  if (w_pool.has_request(bid))
157  {
158  busy_entry wp_request = w_pool.steal_request(bid);
159  STXXL_VERBOSE1("prefetch_pool::hint2 bid=" << bid << " was in write cache at " << wp_request.first);
160  assert(wp_request.first != 0);
161  w_pool.add(block); //in exchange
162  busy_blocks[bid] = wp_request;
163  return true;
164  }
165  STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " => prefetching");
166  request_ptr req = block->read(bid);
167  busy_blocks[bid] = busy_entry(block, req);
168  return true;
169  }
170  STXXL_VERBOSE2("prefetch_pool::hint2 bid=" << bid << " => no free blocks for prefetching");
171  return false;
172  }
173 
174  bool invalidate(bid_type bid)
175  {
176  busy_blocks_iterator cache_el = busy_blocks.find(bid);
177  if (cache_el == busy_blocks.end())
178  return false;
179 
180  // cancel request if it is a read request, there might be
181  // write requests 'stolen' from a write_pool that may not be canceled
182  if (cache_el->second.second->get_type() == request::READ)
183  cache_el->second.second->cancel();
184  // finish the request
185  cache_el->second.second->wait();
186  ++free_blocks_size;
187  free_blocks.push_back(cache_el->second.first);
188  busy_blocks.erase(cache_el);
189  return true;
190  }
191 
192  bool in_prefetching(bid_type bid)
193  {
194  return (busy_blocks.find(bid) != busy_blocks.end());
195  }
196 
203  request_ptr read(block_type * & block, bid_type bid)
204  {
205  busy_blocks_iterator cache_el = busy_blocks.find(bid);
206  if (cache_el == busy_blocks.end())
207  {
208  // not cached
209  STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => no copy in cache, retrieving to " << block);
210  return block->read(bid);
211  }
212 
213  // cached
214  STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => copy in cache exists");
215  ++free_blocks_size;
216  free_blocks.push_back(block);
217  block = cache_el->second.first;
218  request_ptr result = cache_el->second.second;
219  busy_blocks.erase(cache_el);
220  return result;
221  }
222 
223  request_ptr read(block_type * & block, bid_type bid, write_pool<block_type> & w_pool)
224  {
225  // try cache
226  busy_blocks_iterator cache_el = busy_blocks.find(bid);
227  if (cache_el != busy_blocks.end())
228  {
229  // cached
230  STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => copy in cache exists");
231  ++free_blocks_size;
232  free_blocks.push_back(block);
233  block = cache_el->second.first;
234  request_ptr result = cache_el->second.second;
235  busy_blocks.erase(cache_el);
236  return result;
237  }
238 
239  // try w_pool cache
240  if (w_pool.has_request(bid))
241  {
242  busy_entry wp_request = w_pool.steal_request(bid);
243  STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " was in write cache at " << wp_request.first);
244  assert(wp_request.first != 0);
245  w_pool.add(block); //in exchange
246  block = wp_request.first;
247  return wp_request.second;
248  }
249 
250  // not cached
251  STXXL_VERBOSE1("prefetch_pool::read bid=" << bid << " => no copy in cache, retrieving to " << block);
252  return block->read(bid);
253  }
254 
261  unsigned_type resize(unsigned_type new_size)
262  {
263  int_type diff = int_type(new_size) - int_type(size());
264  if (diff > 0)
265  {
266  free_blocks_size += diff;
267  while (--diff >= 0)
268  free_blocks.push_back(new block_type);
269 
270 
271  return size();
272  }
273 
274  while (diff < 0 && free_blocks_size > 0)
275  {
276  ++diff;
277  --free_blocks_size;
278  delete free_blocks.back();
279  free_blocks.pop_back();
280  }
281  return size();
282  }
283 };
284 
286 
287 __STXXL_END_NAMESPACE
288 
289 namespace std
290 {
291  template <class BlockType>
292  void swap(stxxl::prefetch_pool<BlockType> & a,
293  stxxl::prefetch_pool<BlockType> & b)
294  {
295  a.swap(b);
296  }
297 }
298 
299 #endif // !STXXL_PREFETCH_POOL_HEADER
300 // vim: et:ts=4:sw=4
bool hint(bid_type bid)
Gives a hint for prefetching a block.
Definition: prefetch_pool.h:121
Implements dynamically resizable prefetching pool.
Definition: prefetch_pool.h:34
Implements dynamically resizable buffered writing pool.
Definition: write_pool.h:36
unsigned_type resize(unsigned_type new_size)
Resizes size of the pool.
Definition: prefetch_pool.h:261
prefetch_pool(unsigned_type init_size=1)
Constructs pool.
Definition: prefetch_pool.h:76
request_ptr read(block_type *&block, bid_type bid)
Reads block. If this block is cached block is not read but passed from the cache. ...
Definition: prefetch_pool.h:203
Implemented as reference counting smart pointer.
Definition: request_ptr.h:34
unsigned_type size() const
Returns number of owned blocks.
Definition: prefetch_pool.h:112
virtual ~prefetch_pool()
Waits for completion of all ongoing read requests and frees memory.
Definition: prefetch_pool.h:91