14 #ifndef STXXL_CONTAINERS_HASH_MAP_BLOCK_CACHE_HEADER
15 #define STXXL_CONTAINERS_HASH_MAP_BLOCK_CACHE_HEADER
17 #ifdef STXXL_BOOST_CONFIG
18 #include <boost/config.hpp>
34 template <
class BlockType>
39 typedef typename block_type::bid_type
bid_type;
50 blocks_.reserve(size);
51 free_blocks_.reserve(size);
56 free_blocks_.push_back(i);
64 if (free_blocks_.empty()) {
66 busy_blocks_.pop_front();
68 if (reqs_[i_buffer].valid())
69 reqs_[i_buffer]->wait();
71 free_blocks_.push_back(i_buffer);
75 free_blocks_.pop_back();
78 blocks_[i_buffer] = write_block;
79 reqs_[i_buffer] = blocks_[i_buffer]->write(bid);
80 busy_blocks_.push_back(i_buffer);
87 while (!busy_blocks_.empty()) {
89 busy_blocks_.pop_front();
90 if (reqs_[i_buffer].valid())
91 reqs_[i_buffer]->wait();
96 free_blocks_.push_back(i);
101 std::swap(blocks_, obj.
blocks_);
102 std::swap(reqs_, obj.
reqs_);
117 template <
class BlockType>
131 return (a.storage == b.storage && a.offset == b.offset);
139 return longhash1(bid.offset + reinterpret_cast<uint64>(bid.storage));
144 return (a.storage < b.storage) ||
145 (a.storage == b.storage && a.offset < b.offset);
161 enum { valid_all = block_type::size };
196 : write_buffer_(
config::get_instance()->disks_number() * 2),
199 retain_count_(cache_size),
200 dirty_(cache_size, false),
201 valid_subblock_(cache_size),
202 free_blocks_(cache_size),
222 return blocks_.size();
229 for (
typename bid_map_type::const_iterator i = bid_map_.begin();
230 i != bid_map_.end(); ++i)
234 if (reqs_[i_block].valid())
235 reqs_[i_block]->wait();
237 if (dirty_[i_block]) {
239 write_buffer_.write(blocks_[i_block], bids_[i_block]);
242 write_buffer_.flush();
259 i_block2kick = pager_.kick();
262 throw std::runtime_error(
263 "The block cache is too small,"
264 "no block can be kicked out (all blocks are retained)!"
267 pager_.hit(i_block2kick);
268 }
while (retain_count_[i_block2kick] > 0);
270 if (valid_subblock_[i_block2kick] == valid_all &&
271 reqs_[i_block2kick].valid())
273 reqs_[i_block2kick]->wait();
276 if (dirty_[i_block2kick])
278 blocks_[i_block2kick] =
279 write_buffer_.write(blocks_[i_block2kick], bids_[i_block2kick]);
285 bid_map_.erase(bids_[i_block2kick]);
286 free_blocks_.push_back(i_block2kick);
298 typename bid_map_type::const_iterator it = bid_map_.find(bid);
299 if (it == bid_map_.end())
303 retain_count_[i_block]++;
315 typename bid_map_type::const_iterator it = bid_map_.find(bid);
316 if (it == bid_map_.end())
320 if (retain_count_[i_block] == 0)
323 retain_count_[i_block]--;
333 typename bid_map_type::const_iterator it = bid_map_.find(bid);
334 if (it == bid_map_.end())
340 if (valid_subblock_[i_block] != valid_all)
342 reqs_[i_block] = blocks_[i_block]->read(bid);
343 valid_subblock_[i_block] = valid_all;
346 if (reqs_[i_block].valid()) {
347 if (reqs_[i_block]->poll() ==
false)
348 reqs_[i_block]->wait();
351 dirty_[i_block] =
true;
368 typename bid_map_type::const_iterator it = bid_map_.find(bid);
369 if (it != bid_map_.end())
371 i_block = (*it).second;
372 block = blocks_[i_block];
375 if (valid_subblock_[i_block] == valid_all ||
376 valid_subblock_[i_block] == i_subblock)
380 if (valid_subblock_[i_block] == valid_all &&
381 reqs_[i_block].valid())
384 if (reqs_[i_block]->poll() ==
false)
385 reqs_[i_block]->wait();
388 return &((*block)[i_subblock]);
407 if (free_blocks_.empty())
410 i_block = free_blocks_.back(), free_blocks_.pop_back();
411 block = blocks_[i_block];
413 bid_map_[bid] = i_block;
414 bids_[i_block] = bid;
415 dirty_[i_block] =
false;
416 retain_count_[i_block] = 0;
421 bid.storage, bid.offset + i_subblock * subblock_type::raw_size
423 request_ptr req = ((*block)[i_subblock]).read(subblock_bid);
426 valid_subblock_[i_block] = i_subblock;
429 return &((*block)[i_subblock]);
439 typename bid_map_type::const_iterator it = bid_map_.find(bid);
440 if (it != bid_map_.end())
442 i_block = (*it).second;
445 if (valid_subblock_[i_block] == valid_all) {
455 if (free_blocks_.empty())
458 i_block = free_blocks_.back(), free_blocks_.pop_back();
460 bid_map_[bid] = i_block;
461 bids_[i_block] = bid;
462 retain_count_[i_block] = 0;
463 dirty_[i_block] =
false;
467 reqs_[i_block] = blocks_[i_block]->read(bid);
468 valid_subblock_[i_block] = valid_all;
475 for (
typename bid_map_type::const_iterator i = bid_map_.begin();
476 i != bid_map_.end(); ++i)
482 write_buffer_.write(blocks_[i_block], bids_[i_block]);
484 dirty_[i_block] =
false;
487 write_buffer_.flush();
493 free_blocks_.clear();
496 if (reqs_[i].valid()) {
501 free_blocks_.push_back(i);
510 o <<
"Blocks found : " << n_found <<
" (" << 100. * double(n_found) / double(n_read) <<
"%)" << std::endl;
511 o <<
"Blocks not found : " << n_not_found << std::endl;
512 o <<
"Blocks read : " << n_read << std::endl;
513 o <<
"Blocks written : " << n_written << std::endl;
514 o <<
"Clean blocks forced from the cache: " << n_clean_forced << std::endl;
515 o <<
"Wrong subblock cached : " << n_wrong_subblock << std::endl;
526 n_wrong_subblock = 0;
534 std::swap(blocks_, obj.
blocks_);
535 std::swap(bids_, obj.
bids_);
538 std::swap(dirty_, obj.
dirty_);
542 std::swap(reqs_, obj.
reqs_);
545 std::swap(pager_, obj.
pager_);
547 std::swap(n_found, obj.
n_found);
548 std::swap(n_not_found, obj.
n_found);
549 std::swap(n_read, obj.
n_read);
555 #if 0 // for debugging, requires data items to be ostream-able.
558 void dump_cache(std::ostream& os)
const
560 for (
size_t i = 0; i < blocks_.size(); i++)
562 bid_type bid = bids_[i];
563 if (bid_map_.count(bid) == 0) {
564 os <<
"Block " << i <<
": empty\n";
568 os <<
"Block " << i <<
": bid=" << bids_[i]
569 <<
" dirty=" << dirty_[i]
570 <<
" retain_count=" << retain_count_[i]
571 <<
" valid_subblock=" << valid_subblock_[i] <<
"\n";
573 for (
size_t k = 0; k < block_type::size; k++) {
574 os <<
" Subbblock " << k <<
": ";
575 if (valid_subblock_[i] != valid_all && valid_subblock_[i] != k)
580 for (
size_t l = 0; l < block_type::value_type::size; l++) {
581 os <<
"(" << (*blocks_[i])[k][l].first
582 <<
", " << (*blocks_[i])[k][l].second <<
") ";
597 template <
class BlockType>
604 template <
class HashMap>
613 #endif // !STXXL_CONTAINERS_HASH_MAP_BLOCK_CACHE_HEADER
std::vector< unsigned_type > free_blocks_
free blocks as indices to blocks_-vector
bool make_dirty(const bid_type &bid)
Set given block's dirty-flag. Note: If the given block was only partially loaded, it will be complete...
std::vector< bid_type > bids_
bids of cached blocks
void reset_statistics()
Reset all counters to zero.
std::vector< block_type * > blocks_
size_t longhash1(uint64 key_)
std::vector< request_ptr > reqs_
block_cache_write_buffer< block_type > write_buffer_type
block_cache_write_buffer(unsigned_type size)
std::vector< unsigned char > dirty_
true iff block has been altered while in cache
unsigned_type size() const
Return cache-size.
subblock_type * get_subblock(const bid_type &bid, unsigned_type i_subblock)
Retrieve a subblock from the cache. If not yet cached, only the subblock will be loaded.
bool retain_block(const bid_type &bid)
Retain a block in cache. Blocks, that are retained by at least one client, won't get kicked...
void kick_block()
Force a block from the cache; write back to disk if dirty.
bool release_block(const bid_type &bid)
Release a block (decrement retain-count). If the retain-count reaches 0, a block may be kicked again...
std::vector< block_type * > blocks_
cached blocks
block_type::value_type subblock_type
compat_hash_map< bid_type, unsigned_type, bid_hash >::result bid_map_type
Used inside block_cache for buffering write requests of cached blocks.
virtual void wait(bool measure_time=true)=0
Suspends calling thread until completion of the request.
void swap(block_cache_write_buffer &obj)
std::vector< unsigned_type > retain_count_
~block_cache_write_buffer()
block_type::bid_type bid_type
std::list< unsigned_type > busy_blocks_
#define STXXL_BEGIN_NAMESPACE
void clear()
Empty cache; don't write back dirty blocks.
#define STXXL_VERBOSE1(x)
stxxl::lru_pager pager_type
void swap(block_cache &obj)
Exchange contents of two caches.
void prefetch_block(const bid_type &bid)
Load a block in advance.
void flush()
Write all dirty blocks back to disk.
Cache of blocks contained in an external memory hash map. Uses the stxxl::lru_pager as eviction algor...
block_type::bid_type bid_type
choose_int_types< my_pointer_size >::unsigned_type unsigned_type
Main implementation of external memory hash map.
Access point to disks properties. Since 1.4.0: no config files are read automatically! ...
block_cache(unsigned_type cache_size)
Construct a new block-cache.
void print_statistics(std::ostream &o=std::cout) const
Print statistics: Number of hits/misses, blocks forced from cache or written back.
std::vector< unsigned_type > free_blocks_
std::vector< unsigned_type > valid_subblock_
valid_all or the actually loaded subblock's index
block_type * write(block_type *write_block, const bid_type &bid)
Writes the given block back to disk; callers have to exchange the passed block with the returned one!...
std::vector< request_ptr > reqs_
write_buffer_type write_buffer_
#define STXXL_END_NAMESPACE
subblock_type::bid_type subblock_bid_type