Thrill  0.1
block_pool.hpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * thrill/data/block_pool.hpp
3  *
4  * Part of Project Thrill - http://project-thrill.org
5  *
6  * Copyright (C) 2015-2016 Timo Bingmann <[email protected]>
7  *
8  * All rights reserved. Published under the BSD-2 license in the LICENSE file.
9  ******************************************************************************/
10 
11 #pragma once
12 #ifndef THRILL_DATA_BLOCK_POOL_HEADER
13 #define THRILL_DATA_BLOCK_POOL_HEADER
14 
17 #include <thrill/data/block.hpp>
19 #include <thrill/mem/manager.hpp>
20 
21 #include <foxxll/io/request.hpp>
23 
24 #include <algorithm>
25 #include <condition_variable>
26 #include <functional>
27 #include <mutex>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 namespace thrill {
33 namespace data {
34 
35 //! \addtogroup data_layer
36 //! \{
37 
38 /*!
39  * Pool to allocate, keep, swap out/in, and free all ByteBlocks on the host.
40  * Starts a backgroud thread which is responsible for disk I/O
41  */
43 {
44  static constexpr bool debug = false;
45 
46 public:
47  /*!
48  * Creates a simple BlockPool for tests: allows only one thread, enforces no
49  * memory limitations, never swaps to disk.
50  */
51  explicit BlockPool(size_t workers_per_host = 1);
52 
53  //! non-copyable: delete copy-constructor
54  BlockPool(const BlockPool&) = delete;
55  //! non-copyable: delete assignment operator
56  BlockPool& operator = (const BlockPool&) = delete;
57 
58  /*!
59  * Creates a BlockPool with given memory constrains
60  *
61  * \param soft_ram_limit limit (bytes) that causes the BlockPool to swap
62  * out victim pages. Enter 0 for no soft limit
63  *
64  * \param hard_ram_limit limit (bytes) that causes the BlockPool to block
65  * new allocations until some blocks are free'd. Enter 0 for no hard limit.
66  *
67  * \param logger Pointer to logger for output.
68  *
69  * \param mem_manager Memory Manager that tracks amount of RAM
70  * allocated. the BlockPool will create a child manager.
71  *
72  * \param workers_per_host number of workers on this host.
73  */
74  BlockPool(size_t soft_ram_limit, size_t hard_ram_limit,
76  mem::Manager* mem_manager, size_t workers_per_host);
77 
78  //! Checks that all blocks were freed
79  ~BlockPool();
80 
81  //! return number of workers per host
82  size_t workers_per_host() const { return workers_per_host_; }
83 
84  //! Returns logger_
86 
87  //! return next unique File id
88  size_t next_file_id();
89 
90  //! Updates the memory manager for internal memory. If the hard limit is
91  //! reached, the call is blocked intil memory is free'd
92  void RequestInternalMemory(size_t size);
93 
94  //! Updates the memory manager for the internal memory, wakes up waiting
95  //! BlockPool::RequestInternalMemory calls
96  void ReleaseInternalMemory(size_t size);
97 
98  //! Advice the block pool to free up memory in anticipation of a large
99  //! future request.
100  void AdviseFree(size_t size);
101 
102  //! Return any currently being written block (for waiting on completion)
104 
105  //! Evict a Block from the LRU chain into external memory. This can return
106  //! nullptr if no blocks available, or if the Block was not dirty.
108 
109  //! Allocates a byte block with the request size. May block this thread if
110  //! the hard memory limit is reached, until memory is freed by another
111  //! thread. The returned Block is allocated in RAM, but with a zero pin
112  //! count.
113  PinnedByteBlockPtr AllocateByteBlock(size_t size, size_t local_worker_id);
114 
115  //! Allocate a byte block from an external file, used to directly map system
116  //! files to data::File.
118  const foxxll::file_ptr& file, uint64_t offset, size_t size);
119 
120  //! Increment a ByteBlock's pin count, requires the pin count to be > 0.
121  void IncBlockPinCount(ByteBlock* block_ptr, size_t local_worker_id);
122 
123  //! Decrement a ByteBlock's pin count and possibly unpin it.
124  void DecBlockPinCount(ByteBlock* block_ptr, size_t local_worker_id);
125 
126  //! Destroys the block. Called by ByteBlockPtr's deleter.
127  void DestroyBlock(ByteBlock* block_ptr);
128 
129  //! Evict a block into external memory. The block must be unpinned and not
130  //! swapped.
131  void EvictBlock(ByteBlock* block_ptr);
132 
133  //! \name Block Statistics
134  //! \{
135 
136  //! Hard limit on amount of memory used for ByteBlock
137  size_t hard_ram_limit() noexcept;
138 
139  //! Total number of allocated blocks of this block pool
140  size_t total_blocks() noexcept;
141 
142  //! Total number of bytes allocated in blocks of this block pool
143  size_t total_bytes() noexcept;
144 
145  //! Maximum total number of bytes allocated in blocks of this block pool
146  size_t max_total_bytes() noexcept;
147 
148  //! Total number of pinned blocks of this block pool
149  size_t pinned_blocks() noexcept;
150 
151  //! Total number of unpinned blocks in memory of this block pool
152  size_t unpinned_blocks() noexcept;
153 
154  //! Total number of blocks currently begin written.
155  size_t writing_blocks() noexcept;
156 
157  //! Total number of swapped blocks
158  size_t swapped_blocks() noexcept;
159 
160  //! Total number of blocks currently begin read from EM.
161  size_t reading_blocks() noexcept;
162 
163  //! \}
164 
165  //! \name Methods for ProfileTask
166  //! \{
167 
168  void RunTask(const std::chrono::steady_clock::time_point& tp) final;
169 
170  //! \}
171 
172  //! Pins a block by swapping it in if required.
173  PinRequestPtr PinBlock(const Block& block, size_t local_worker_id);
174 
175  //! calculate maximum merging degree from available memory and the number of
176  //! files. additionally calculate the prefetch size of each File.
177  std::pair<size_t, size_t> MaxMergeDegreePrefetch(size_t num_files);
178 
179 private:
180  //! locked before internal state is changed
181  std::mutex mutex_;
182 
183  //! For waiting on read/pin requests to finish (we use only one
184  //! condition_variable for all read requests).
185  std::condition_variable cv_read_complete_;
186 
187  //! reference to HostContext's logger or a null sink
189 
190  //! local Manager counting only ByteBlock allocations in internal memory.
192 
193  //! number of workers per host
195 
196  //! a counter pair where one value is held as the max until written to stats
197  struct Counter;
198 
199  //! substructure containing pin counters
200  struct PinCount;
201 
202  //! pimpl data structure
203  class Data;
204 
205  //! pimpl data structure
206  std::unique_ptr<Data> d_;
207 
208  //! Increment a ByteBlock's pin count - without locking the mutex
209  void IntIncBlockPinCount(ByteBlock* block_ptr, size_t local_worker_id);
210 
211  //! callback for async write of blocks during eviction
212  void OnWriteComplete(ByteBlock* block_ptr, foxxll::request* req, bool success);
213 
214  //! callback for async read of blocks for pin requests
215  void OnReadComplete(PinRequest* read, foxxll::request* req, bool success);
216 
217  //! make ostream-able
218  friend std::ostream& operator << (std::ostream& os, const PinCount& p);
219 
220  //! for calling OnWriteComplete
221  friend class ByteBlock;
222 
223  //! for calling OnReadComplete and access to mutex and cvs
224  friend class PinRequest;
225 };
226 
227 /*!
228  * RAII class for allocating memory from a BlockPool
229  */
231 {
232 public:
233  BlockPoolMemoryHolder(BlockPool& block_pool, size_t size)
234  : block_pool_(block_pool), size_(size) {
235  if (size)
236  block_pool_.RequestInternalMemory(size);
237  }
238 
239  //! non-copyable: delete copy-constructor
241  //! non-copyable: delete assignment operator
243 
245  if (size_)
246  block_pool_.ReleaseInternalMemory(size_);
247  }
248 
249 private:
251  size_t size_;
252 };
253 
254 //! \}
255 
256 } // namespace data
257 } // namespace thrill
258 
259 #endif // !THRILL_DATA_BLOCK_POOL_HEADER
260 
261 /******************************************************************************/
~BlockPool()
Checks that all blocks were freed.
Definition: block_pool.cpp:404
Block combines a reference to a read-only ByteBlock and book-keeping information. ...
Definition: block.hpp:52
void ReleaseInternalMemory(size_t size)
size_t total_blocks() noexcept
Total number of allocated blocks of this block pool.
Definition: block_pool.cpp:867
size_t max_total_bytes() noexcept
Maximum total number of bytes allocated in blocks of this block pool.
Definition: block_pool.cpp:896
void AdviseFree(size_t size)
std::pair< size_t, size_t > MaxMergeDegreePrefetch(size_t num_files)
Definition: block_pool.cpp:703
void OnWriteComplete(ByteBlock *block_ptr, foxxll::request *req, bool success)
callback for async write of blocks during eviction
size_t hard_ram_limit() noexcept
Hard limit on amount of memory used for ByteBlock.
Definition: block_pool.cpp:886
void DecBlockPinCount(ByteBlock *block_ptr, size_t local_worker_id)
Decrement a ByteBlock&#39;s pin count and possibly unpin it.
Definition: block_pool.cpp:818
size_t pinned_blocks() noexcept
Total number of pinned blocks of this block pool.
Definition: block_pool.cpp:914
A pinned / pin-counted pointer to a ByteBlock.
Definition: byte_block.hpp:205
BlockPool(size_t workers_per_host=1)
Creates a simple BlockPool for tests: allows only one thread, enforces no memory limitations, never swaps to disk.
Definition: block_pool.cpp:373
A non-pinned counting pointer to a ByteBlock.
Definition: byte_block.hpp:176
static constexpr bool debug
Definition: block_pool.hpp:44
mem::Manager mem_manager_
local Manager counting only ByteBlock allocations in internal memory.
Definition: block_pool.hpp:191
PinRequestPtr PinBlock(const Block &block, size_t local_worker_id)
Pins a block by swapping it in if required.
Definition: block_pool.cpp:548
void DestroyBlock(ByteBlock *block_ptr)
Destroys the block. Called by ByteBlockPtr&#39;s deleter.
Definition: block_pool.cpp:939
size_t workers_per_host_
number of workers per host
Definition: block_pool.hpp:194
void IncBlockPinCount(ByteBlock *block_ptr, size_t local_worker_id)
Increment a ByteBlock&#39;s pin count, requires the pin count to be > 0.
Definition: block_pool.cpp:796
common::JsonLogger logger_
reference to HostContext&#39;s logger or a null sink
Definition: block_pool.hpp:188
PinnedByteBlockPtr AllocateByteBlock(size_t size, size_t local_worker_id)
Definition: block_pool.cpp:484
std::condition_variable cv_read_complete_
Definition: block_pool.hpp:185
void OnReadComplete(PinRequest *read, foxxll::request *req, bool success)
callback for async read of blocks for pin requests
Definition: block_pool.cpp:723
Pool to allocate, keep, swap out/in, and free all ByteBlocks on the host.
Definition: block_pool.hpp:42
size_t workers_per_host() const
return number of workers per host
Definition: block_pool.hpp:82
BlockPool & operator=(const BlockPool &)=delete
non-copyable: delete assignment operator
A ByteBlock is the basic storage units of containers like File, BlockQueue, etc.
Definition: byte_block.hpp:51
size_t swapped_blocks() noexcept
Total number of swapped blocks.
Definition: block_pool.cpp:929
RAII class for allocating memory from a BlockPool.
Definition: block_pool.hpp:230
size_t writing_blocks() noexcept
Total number of blocks currently begin written.
Definition: block_pool.cpp:924
foxxll::request_ptr EvictBlockLRU()
size_t total_bytes() noexcept
Total number of bytes allocated in blocks of this block pool.
Definition: block_pool.cpp:891
common::JsonLogger & logger()
Returns logger_.
Definition: block_pool.hpp:85
High-performance smart pointer used as a wrapping reference counting pointer.
friend std::ostream & operator<<(std::ostream &os, const PinCount &p)
make ostream-able
Definition: block_pool.cpp:216
size_t reading_blocks() noexcept
Total number of blocks currently begin read from EM.
Definition: block_pool.cpp:934
foxxll::request_ptr GetAnyWriting()
Return any currently being written block (for waiting on completion)
Object shared by allocators and other classes to track memory allocations.
Definition: manager.hpp:28
size_t next_file_id()
return next unique File id
Request object encapsulating basic properties like file and offset.
Definition: request.hpp:49
JsonLogger is a receiver of JSON output objects for logging.
Definition: json_logger.hpp:69
size_t unpinned_blocks() noexcept
Total number of unpinned blocks in memory of this block pool.
Definition: block_pool.cpp:919
void IntIncBlockPinCount(ByteBlock *block_ptr, size_t local_worker_id)
Increment a ByteBlock&#39;s pin count - without locking the mutex.
Definition: block_pool.cpp:803
void EvictBlock(ByteBlock *block_ptr)
BlockPoolMemoryHolder(BlockPool &block_pool, size_t size)
Definition: block_pool.hpp:233
void RunTask(const std::chrono::steady_clock::time_point &tp) final
method called by ProfileThread.
std::mutex mutex_
locked before internal state is changed
Definition: block_pool.hpp:181
std::unique_ptr< Data > d_
pimpl data structure
Definition: block_pool.hpp:203
void RequestInternalMemory(size_t size)
ByteBlockPtr MapExternalBlock(const foxxll::file_ptr &file, uint64_t offset, size_t size)
Definition: block_pool.cpp:528