Stxxl  1.3.2
diskallocator.h
1 /***************************************************************************
2  * include/stxxl/bits/mng/diskallocator.h
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2002-2004 Roman Dementiev <[email protected]>
7  * Copyright (C) 2007 Johannes Singler <[email protected]>
8  * Copyright (C) 2009, 2010 Andreas Beckmann <[email protected]>
9  *
10  * Distributed under the Boost Software License, Version 1.0.
11  * (See accompanying file LICENSE_1_0.txt or copy at
12  * http://www.boost.org/LICENSE_1_0.txt)
13  **************************************************************************/
14 
15 #ifndef STXXL_DISKALLOCATOR_HEADER
16 #define STXXL_DISKALLOCATOR_HEADER
17 
18 #include <vector>
19 #include <map>
20 #include <algorithm>
21 
22 #include <stxxl/bits/noncopyable.h>
23 #include <stxxl/bits/parallel.h>
24 #include <stxxl/bits/mng/bid.h>
25 #include <stxxl/bits/verbose.h>
26 #include <stxxl/bits/io/file.h>
27 
28 
29 __STXXL_BEGIN_NAMESPACE
30 
33 
34 class DiskAllocator : private noncopyable
35 {
36  typedef std::pair<stxxl::int64, stxxl::int64> place;
37 
38  struct FirstFit : public std::binary_function<place, stxxl::int64, bool>
39  {
40  bool operator () (
41  const place & entry,
42  const stxxl::int64 size) const
43  {
44  return (entry.second >= size);
45  }
46  };
47 
48  typedef std::map<stxxl::int64, stxxl::int64> sortseq;
49 
50  stxxl::mutex mutex;
51  sortseq free_space;
52  stxxl::int64 free_bytes;
53  stxxl::int64 disk_bytes;
54  stxxl::file * storage;
55  bool autogrow;
56 
57  void dump() const;
58 
59  void deallocation_error(
60  stxxl::int64 block_pos, stxxl::int64 block_size,
61  const sortseq::iterator & pred, const sortseq::iterator & succ) const;
62 
63  // expects the mutex to be locked to prevent concurrent access
64  void add_free_region(stxxl::int64 block_pos, stxxl::int64 block_size);
65 
66  // expects the mutex to be locked to prevent concurrent access
67  void grow_file(stxxl::int64 extend_bytes)
68  {
69  if (!extend_bytes)
70  return;
71 
72  storage->set_size(disk_bytes + extend_bytes);
73  add_free_region(disk_bytes, extend_bytes);
74  disk_bytes += extend_bytes;
75  }
76 
77 public:
78  DiskAllocator(stxxl::file * storage, stxxl::int64 disk_size) :
79  free_bytes(0),
80  disk_bytes(0),
81  storage(storage),
82  autogrow(disk_size == 0)
83  {
84  grow_file(disk_size);
85  }
86 
87  inline stxxl::int64 get_free_bytes() const
88  {
89  return free_bytes;
90  }
91 
92  inline stxxl::int64 get_used_bytes() const
93  {
94  return disk_bytes - free_bytes;
95  }
96 
97  inline stxxl::int64 get_total_bytes() const
98  {
99  return disk_bytes;
100  }
101 
102  template <unsigned BLK_SIZE>
103  void new_blocks(BIDArray<BLK_SIZE> & bids)
104  {
105  new_blocks(bids.begin(), bids.end());
106  }
107 
108  template <unsigned BLK_SIZE>
109  void new_blocks(BID<BLK_SIZE> * begin, BID<BLK_SIZE> * end);
110 
111 #if 0
112  template <unsigned BLK_SIZE>
113  void delete_blocks(const BIDArray<BLK_SIZE> & bids)
114  {
115  for (unsigned i = 0; i < bids.size(); ++i)
116  delete_block(bids[i]);
117  }
118 #endif
119 
120  template <unsigned BLK_SIZE>
121  void delete_block(const BID<BLK_SIZE> & bid)
122  {
123  scoped_mutex_lock lock(mutex);
124 
125  STXXL_VERBOSE2("DiskAllocator::delete_block<" << BLK_SIZE <<
126  ">(pos=" << bid.offset << ", size=" << bid.size <<
127  "), free:" << free_bytes << " total:" << disk_bytes);
128 
129  add_free_region(bid.offset, bid.size);
130  }
131 };
132 
133 template <unsigned BLK_SIZE>
134 void DiskAllocator::new_blocks(BID<BLK_SIZE> * begin, BID<BLK_SIZE> * end)
135 {
136  stxxl::int64 requested_size = 0;
137 
138  for (typename BIDArray<BLK_SIZE>::iterator cur = begin; cur != end; ++cur)
139  {
140  STXXL_VERBOSE2("Asking for a block with size: " << (cur->size));
141  requested_size += cur->size;
142  }
143 
144  scoped_mutex_lock lock(mutex);
145 
146  STXXL_VERBOSE2("DiskAllocator::new_blocks<BLK_SIZE>, BLK_SIZE = " << BLK_SIZE <<
147  ", free:" << free_bytes << " total:" << disk_bytes <<
148  ", blocks: " << (end - begin) <<
149  " begin: " << static_cast<void *>(begin) <<
150  " end: " << static_cast<void *>(end) <<
151  ", requested_size=" << requested_size);
152 
153  if (free_bytes < requested_size)
154  {
155  if (!autogrow) {
156  STXXL_ERRMSG("External memory block allocation error: " << requested_size <<
157  " bytes requested, " << free_bytes <<
158  " bytes free. Trying to extend the external memory space...");
159  }
160 
161  grow_file(requested_size);
162  }
163 
164  // dump();
165 
166  sortseq::iterator space;
167  space = std::find_if(free_space.begin(), free_space.end(),
168  bind2nd(FirstFit(), requested_size) _STXXL_FORCE_SEQUENTIAL);
169 
170  if (space == free_space.end() && requested_size == BLK_SIZE)
171  {
172  assert(end - begin == 1);
173 
174  STXXL_ERRMSG("Warning: Severe external memory space fragmentation!");
175  dump();
176 
177  STXXL_ERRMSG("External memory block allocation error: " << requested_size <<
178  " bytes requested, " << free_bytes <<
179  " bytes free. Trying to extend the external memory space...");
180 
181  grow_file(BLK_SIZE);
182 
183  space = std::find_if(free_space.begin(), free_space.end(),
184  bind2nd(FirstFit(), requested_size) _STXXL_FORCE_SEQUENTIAL);
185  }
186 
187  if (space != free_space.end())
188  {
189  stxxl::int64 region_pos = (*space).first;
190  stxxl::int64 region_size = (*space).second;
191  free_space.erase(space);
192  if (region_size > requested_size)
193  free_space[region_pos + requested_size] = region_size - requested_size;
194 
195  for (stxxl::int64 pos = region_pos; begin != end; ++begin)
196  {
197  begin->offset = pos;
198  pos += begin->size;
199  }
200  free_bytes -= requested_size;
201  //dump();
202 
203  return;
204  }
205 
206  // no contiguous region found
207  STXXL_VERBOSE1("Warning, when allocating an external memory space, no contiguous region found");
208  STXXL_VERBOSE1("It might harm the performance");
209 
210  assert(requested_size > BLK_SIZE);
211  assert(end - begin > 1);
212 
213  lock.unlock();
214 
215  BID<BLK_SIZE> * middle = begin + ((end - begin) / 2);
216  new_blocks(begin, middle);
217  new_blocks(middle, end);
218 }
219 
221 
222 __STXXL_END_NAMESPACE
223 
224 #endif // !STXXL_DISKALLOCATOR_HEADER
225 // vim: et:ts=4:sw=4
Block size.
Definition: bid.h:44
Aquire a lock that&#39;s valid until the end of scope.
Definition: mutex.h:82
stxxl::int64 offset
offset within the file of the block
Definition: bid.h:49