MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
buddy.cpp
1 /*
2  Copyright (C) 2003-2006 MySQL AB
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include "buddy.hpp"
20 
21 void Chunk256::setFree(bool free){
22  // Bit 0 of allocationTimeStamp represents if the segment is free or not
23  Uint32 offMask = 0x0; // A mask to set the 0 bit to 0
24  allocationTimeStamp = 0x0;
25  if(free)
26  // Set this bit to 0, if segment should be free
27  allocationTimeStamp = allocationTimeStamp & offMask;
28 }
29 
30 bool Chunk256::getFree(){
31  Uint32 offMask = 0x0;
32  return ((allocationTimeStamp | offMask) == offMask ? true : false);
33 }
34 
35 void Chunk256::setAllocationTimeStamp(Uint32 cTime){
36  // Bits 1-31 of allocationTimeStamp represent the allocation time for segment
37 
38  // printf("\nSet allocation time. Current time %d", cTime);
39  Uint32 onMask = 0x80000000; // A mask to set the 0 bit to 1
40  allocationTimeStamp = 0x0;
41  allocationTimeStamp = onMask | cTime;
42 }
43 
44 Uint32 Chunk256::getAllocationTimeStamp(){
45  Uint32 onMask = 0x80000000;
46  allocationTimeStamp = allocationTimeStamp ^ onMask;
47  printf("\nGet allocation time. Time is %d", allocationTimeStamp);
48  return allocationTimeStamp;
49 };
50 
51 bool BuddyMemory::allocate(int nChunksToAllocate) {
52 
53  // Allocate the memory block needed. This memory is deallocated in the
54  // destructor of TransporterRegistry.
55 
56  printf("\nAllocating %d chunks...", nChunksToAllocate);
57 
58  startOfMemoryBlock = (Uint32*) malloc(256 * nChunksToAllocate);
59 
60  if (startOfMemoryBlock == NULL)
61  return false;
62 
63  // Allocate the array of 256-byte chunks
64  chunk = new Chunk256[nChunksToAllocate];
65 
66  // Initialize the chunk-array. Every 8 kB segment consists of 32 chunks.
67  // Set all chunks to free and set the prev and next pointer
68  for (int i=0; i < nChunksToAllocate; i++) {
69  chunk[i].setFree(true);
70  if (i%32 == 0) {
71  // The first chunk in every segment will point to the prev and next segment
72  chunk[i].prevSegmentOfSameSize = i-32;
73  chunk[i].nextSegmentOfSameSize = i + 32;
74  chunk[0].prevSegmentOfSameSize = END_OF_CHUNK_LIST;
75  chunk[totalNoOfChunks-32].nextSegmentOfSameSize = END_OF_CHUNK_LIST;
76  } else {
77  // The rest of the chunks in the segments have undefined prev and next pointers
78  chunk[i].prevSegmentOfSameSize = UNDEFINED_CHUNK;
79  chunk[i].nextSegmentOfSameSize = UNDEFINED_CHUNK;
80  }
81  }
82 
83  // Initialize the freeSegment-pointers
84  for (int i=0; i<sz_MAX; i++)
85  freeSegment[i] = UNDEFINED_CHUNK;
86 
87  // There are only 8 kB segments at startup
88  freeSegment[sz_8192] = 0;
89 
90  for (int i=0; i<sz_MAX; i++)
91  printf("\nPointers: %d", freeSegment[i]);
92 
93  return true;
94 }
95 
96 
97 bool BuddyMemory::getSegment(Uint32 size, Segment * dst) {
98 
99  // The no of chunks the user asked for
100  Uint32 nChunksAskedFor = ceil((double(size)/double(256)));
101  int segm;
102 
103  printf("\n%d chunks asked for", nChunksAskedFor);
104 
105  // It may be that the closest segment size above
106  // nChunksAskedFor*256 is not a size that is available in
107  // the freeSegment-list, i.e. it may not be of FreeSegmentSize.
108  int nChunksToAllocate = nChunksAskedFor;
109 
110  // Find the FreeSegmentSize closest above nChunksAskedFor
111  if ((nChunksToAllocate != 1) && (nChunksToAllocate % 2 != 0))
112  nChunksToAllocate++;
113 
114  printf("\n%d chunks to allocate", nChunksToAllocate);
115  int segmSize = logTwoPlus(nChunksToAllocate) - 1;
116  if (size-pow(2,segmSize) > 256)
117  segmSize ++;
118  printf("\nSegment size: %f", pow(2,int(8+segmSize)));
119 
120  while ((segmSize <= sz_GET_MAX) && (freeSegment[segmSize] == UNDEFINED_CHUNK))
121  segmSize++;
122 
123  segm = freeSegment[segmSize];
124  if (segm != UNDEFINED_CHUNK){
125  // Free segment of asked size or larger is found
126 
127  // Remove the found segment from the freeSegment-list
128  removeFromFreeSegmentList(segmSize, segm);
129 
130  // Set all chunks to allocated (not free) and set the allocation time
131  // for the segment we are about to allocate
132  for (int i = segm; i <= segm+nChunksToAllocate; i++) {
133  chunk[i].setFree(false);
134  chunk[i].setAllocationTimeStamp(currentTime);
135  }
136 
137  // Before returning the segment, check if it is larger than the segment asked for
138  if (nChunksAskedFor < nChunksToAllocate)
139  release(nChunksAskedFor, nChunksToAllocate - nChunksAskedFor - 1);
140 
141  Segment segment;
142  segment.segmentAddress = startOfMemoryBlock+(segm * 256);
143  segment.segmentSize = 256 * nChunksAskedFor;
144  segment.releaseId = segm;
145 
146  printf("\nSegment: segment address = %d, segment size = %d, release Id = %d",
147  segment.segmentAddress, segment.segmentSize, segment.releaseId);
148 
149  return true;
150  }
151  printf("\nNo segments of asked size or larger are found");
152  return false;
153 }
154 
155 void BuddyMemory::removeFromFreeSegmentList(int sz, int index) {
156  // Remove the segment from the freeSegment list
157 
158  printf("\nRemoving segment from list...");
159  if (index != UNDEFINED_CHUNK) {
160  Chunk256 prevChunk;
161  Chunk256 nextChunk;
162  int prevChunkIndex = chunk[index].prevSegmentOfSameSize;
163  int nextChunkIndex = chunk[index].nextSegmentOfSameSize;
164 
165  if (prevChunkIndex == END_OF_CHUNK_LIST) {
166  if (nextChunkIndex == END_OF_CHUNK_LIST)
167  // We are about to remove the only element in the list
168  freeSegment[sz] = UNDEFINED_CHUNK;
169  else {
170  // We are about to remove the first element in the list
171  nextChunk = chunk[nextChunkIndex];
172  nextChunk.prevSegmentOfSameSize = END_OF_CHUNK_LIST;
173  freeSegment[sz] = nextChunkIndex;
174  }
175  } else {
176  if (nextChunkIndex == END_OF_CHUNK_LIST) {
177  // We are about to remove the last element in the list
178  prevChunk = chunk[prevChunkIndex];
179  prevChunk.nextSegmentOfSameSize = END_OF_CHUNK_LIST;
180  } else {
181  // We are about to remove an element in the middle of the list
182  prevChunk = chunk[prevChunkIndex];
183  nextChunk = chunk[nextChunkIndex];
184  prevChunk.nextSegmentOfSameSize = nextChunkIndex;
185  nextChunk.prevSegmentOfSameSize = prevChunkIndex;
186  }
187  }
188  }
189  for (int i=0; i<sz_MAX; i++)
190  printf("\nPointers: %d", freeSegment[i]);
191 }
192 
193 void BuddyMemory::release(int releaseId, int size) {
194 
195  int nChunksToRelease = (size == 0 ? 1 : ceil(double(size)/double(256)));
196  //nChunksToRelease = ceil(double(size)/double(256));
197  int startChunk = releaseId;
198  int endChunk = releaseId + nChunksToRelease - 1;
199 
200  printf("\n%d chunks to release (initially)", nChunksToRelease);
201 
202  // Set the chunks we are about to release to free
203  for (int i = startChunk; i <= endChunk; i++){
204  chunk[i].setFree(true);
205  }
206 
207  // Look at the chunks before the segment we are about to release
208  for (int i = releaseId-1; i >= 0; i--) {
209  if (!chunk[i].getFree())
210  break;
211  else {
212  startChunk = i;
213  nChunksToRelease++;
214  // Look at the next-pointer. If it is valid, we have a
215  // chunk that is the start of a free segment. Remove it
216  // from the freeSegment-list.
217  if (chunk[i].nextSegmentOfSameSize != UNDEFINED_CHUNK)
218  removeFromFreeSegmentList(size, i);
219  }
220  }
221 
222  // Look at the chunks after the segment we are about to release
223  for (int i = endChunk+1; i <= totalNoOfChunks; i++) {
224  if (!chunk[i].getFree())
225  break;
226  else {
227  endChunk = i;
228  nChunksToRelease++;
229  // Look at the next-pointer. If it is valid, we have a
230  // chunk that is the start of a free segment. Remove it
231  // from the free segment list
232  if (chunk[i].nextSegmentOfSameSize != UNDEFINED_CHUNK)
233  removeFromFreeSegmentList(size, i);
234  }
235  }
236 
237  // We have the start and end indexes and total no of free chunks.
238  // Separate the chunks into segments that can be added to the
239  // freeSegments-list.
240  int restChunk = 0;
241  int segmSize;
242 
243  printf("\n%d chunks to release (finally)", nChunksToRelease);
244 
245  segmSize = logTwoPlus(nChunksToRelease) - 1;
246  if (segmSize > sz_MAX) {
247  segmSize = sz_MAX;
248  }
249 
250  nChunksToRelease = pow(2,segmSize);
251  addToFreeSegmentList(nChunksToRelease*256, startChunk);
252 }
253 
254 void BuddyMemory::addToFreeSegmentList(int sz, int index) {
255  // Add a segment to the freeSegment list
256 
257  printf("\nAsked to add segment of size %d", sz);
258 
259  // Get an index in freeSegment list corresponding to sz size
260  int segmSize = logTwoPlus(sz) - 1;
261  if (sz - pow(2,segmSize) >= 256)
262  segmSize ++;
263  sz = segmSize - 8;
264 
265  int nextSegm = freeSegment[sz];
266 
267  printf("\nAdding a segment of size %f", pow(2,(8 + sz)));
268 
269  freeSegment[sz] = index;
270  if (nextSegm == UNDEFINED_CHUNK) {
271  // We are about to add a segment to an empty list
272  chunk[index].prevSegmentOfSameSize = END_OF_CHUNK_LIST;
273  chunk[index].nextSegmentOfSameSize = END_OF_CHUNK_LIST;
274  }
275  else {
276  // Add the segment first in the list
277  chunk[index].prevSegmentOfSameSize = END_OF_CHUNK_LIST;
278  chunk[index].nextSegmentOfSameSize = nextSegm;
279  chunk[nextSegm].prevSegmentOfSameSize = index;
280  }
281 
282  for (int i=0; i<sz_MAX; i++)
283  printf("\nPointers: %d", freeSegment[i]);
284 
285 }
286 
287 Uint32 BuddyMemory::logTwoPlus(Uint32 arg) {
288  // Calculate log2(arg) + 1
289 
290  Uint32 resValue;
291 
292  arg = arg | (arg >> 8);
293  arg = arg | (arg >> 4);
294  arg = arg | (arg >> 2);
295  arg = arg | (arg >> 1);
296  resValue = (arg & 0x5555) + ((arg >> 1) & 0x5555);
297  resValue = (resValue & 0x3333) + ((resValue >> 2) & 0x3333);
298  resValue = resValue + (resValue >> 4);
299  resValue = (resValue & 0xf) + ((resValue >> 8) & 0xf);
300 
301  return resValue;
302 }
303 
304 bool BuddyMemory::memoryAvailable() {
305  // Return true if there is at least 8 kB memory available
306  for (int i = sz_8192; i < sz_MAX; i++)
307  if (freeSegment[i] != UNDEFINED_CHUNK)
308  return true;
309  return false;
310 }
311 
312 
313 void BuddyMemory::refreshTime(Uint32 time) {
314  if (time - currentTime > 1000) {
315  // Update current time
316  currentTime = time;
317  // Go through the chunk-list every second and release
318  // any chunks that have been allocated for too long
319  for (int i=0; i<totalNoOfChunks; i++) {
320  if ((!chunk[i].getFree()) &&
321  (currentTime-chunk[i].getAllocationTimeStamp() > ALLOCATION_TIMEOUT)) {
322  release(i, 256);
323  printf("\nChunks hve been allocated for too long");
324  }
325  }
326  }
327 }