2 * Copyright (c) 2008-2009,2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
27 #include "ExtentManager.h"
30 ExtentManager::Init(uint32_t theBlockSize
, uint32_t theNativeBlockSize
, off_t theTotalBytes
)
32 blockSize
= theBlockSize
;
33 nativeBlockSize
= theNativeBlockSize
;
34 totalBytes
= theTotalBytes
;
35 totalBlocks
= howmany(totalBytes
, blockSize
);
37 // add sentry empty extents at both sides so empty partition doesn't need to be handled specially
38 AddBlockRangeExtent(0, 0);
39 AddBlockRangeExtent(totalBlocks
, 0);
43 ExtentManager::MergeExtent(const ExtentInfo
&a
, const ExtentInfo
&b
, ExtentInfo
*c
)
45 // merge ext into *curIt
46 c
->blockAddr
= min(a
.blockAddr
, b
.blockAddr
);
47 c
->numBlocks
= max(a
.blockAddr
+ a
.numBlocks
, b
.blockAddr
+ b
.numBlocks
) - c
->blockAddr
;
51 ExtentManager::AddBlockRangeExtent(off_t blockAddr
, off_t numBlocks
)
53 struct ExtentInfo ext
, newExt
;
54 ListExtIt curIt
, newIt
;
57 // make the range a valid range
58 if ((blockAddr
> totalBlocks
) || (blockAddr
+ numBlocks
< 0)) { // totally out of range, do nothing
62 numBlocks
= blockAddr
+ numBlocks
;
65 if (blockAddr
+ numBlocks
> totalBlocks
) {
66 numBlocks
= totalBlocks
- blockAddr
;
69 ext
.blockAddr
= blockAddr
;
70 ext
.numBlocks
= numBlocks
;
72 for (curIt
= extentList
.begin(); curIt
!= extentList
.end(); curIt
++) {
73 if (BeforeExtent(ext
, *curIt
))
75 if (!BeforeExtent(*curIt
, ext
)) { // overlapped extents
76 MergeExtent(ext
, *curIt
, &newExt
);
83 // insert ext before curIt
85 curIt
= extentList
.insert(curIt
, ext
); // throws bad_alloc when out of memory
90 curIt
= extentList
.begin();
91 while (curIt
!= extentList
.end()) {
92 if (curIt
== newIt
|| BeforeExtent(*curIt
, *newIt
)) { // curIt is before newIt
96 if (BeforeExtent(*newIt
, *curIt
)) { // curIt is after newIt now, we are done
99 // merge the two extents
100 MergeExtent(*curIt
, *newIt
, &newExt
);
102 curIt
= extentList
.erase(curIt
);
104 // printf("After %s(%lld, %lld)\n", __func__, blockAddr, numBlocks); DebugPrint();
105 } // ExtentManager::AddBlockRangeExtent
108 ExtentManager::RemoveBlockRangeExtent(off_t blockAddr
, off_t numBlocks
)
110 struct ExtentInfo ext
, newExt
;
113 ext
.blockAddr
= blockAddr
;
114 ext
.numBlocks
= numBlocks
;
116 curIt
= extentList
.begin();
117 while (curIt
!= extentList
.end()) {
118 if (BeforeExtent(*curIt
, ext
)) {
122 if (BeforeExtent(ext
, *curIt
)) // we are done
126 // If we get here, the input extent and *curIt have at least one block in common.
127 // That is, they overlap in some way. Thus *curIt needs to change, be removed,
128 // or be split into two non-contiguous extents.
131 if (curIt
->blockAddr
>= ext
.blockAddr
&&
132 curIt
->blockAddr
+ curIt
->numBlocks
<= ext
.blockAddr
+ ext
.numBlocks
) {
134 // The input extent totally contains *curIt, so remove *curIt.
136 curIt
= extentList
.erase(curIt
);
137 } else if (curIt
->blockAddr
< ext
.blockAddr
&&
138 curIt
->blockAddr
+ curIt
->numBlocks
> ext
.blockAddr
+ ext
.numBlocks
) {
140 // The input extent does not include the start of *curIt, nor the end of *curIt,
141 // so split *curIt into two extents.
143 newExt
.blockAddr
= ext
.blockAddr
+ ext
.numBlocks
;
144 newExt
.numBlocks
= curIt
->blockAddr
+ curIt
->numBlocks
- newExt
.blockAddr
;
145 curIt
->numBlocks
= ext
.blockAddr
- curIt
->blockAddr
;
147 extentList
.insert(curIt
, newExt
); // throws bad_alloc when out of memory
151 // The input extent contains either the start or the end of *curIt, but not both.
152 // The remove will leave either the end or the start of *curIt (respectively) and
153 // not change the number of extents in the list.
155 if (curIt
->blockAddr
>= ext
.blockAddr
) {
157 // Remove the start of *curIt by updating both its starting block and size.
159 assert(curIt
->blockAddr
+ curIt
->numBlocks
> ext
.blockAddr
+ ext
.numBlocks
);
160 newExt
.blockAddr
= ext
.blockAddr
+ ext
.numBlocks
;
161 newExt
.numBlocks
= curIt
->blockAddr
+ curIt
->numBlocks
- newExt
.blockAddr
;
165 // Remove the end of *curIt by updating its size.
167 curIt
->numBlocks
= ext
.blockAddr
- curIt
->blockAddr
;
172 //printf("After %s(%lld, %lld)\n", __func__, blockAddr, numBlocks); DebugPrint();
176 ExtentManager::AddByteRangeExtent(off_t byteAddr
, off_t numBytes
)
178 off_t blockAddr
= byteAddr
/ blockSize
;
179 off_t blockAddrOfLastByte
= (byteAddr
+ numBytes
- 1) / blockSize
;
180 off_t numBlocks
= blockAddrOfLastByte
- blockAddr
+ 1;
181 AddBlockRangeExtent(blockAddr
, numBlocks
);
185 ExtentManager::DebugPrint()
189 for (it
= extentList
.begin(); it
!= extentList
.end(); it
++) {
190 printf("[%lld, %lld] ", it
->blockAddr
, it
->numBlocks
);
199 clang++ -arch i386 -arch x86_64 -DUNIT_TEST ExtentManager.cpp -o ExtentManager && ./ExtentManager
205 const char *DebugDescription(class ExtentManager
*extMan
)
207 char *result
= strdup("");
212 for (it
= extMan
->extentList
.begin(); it
!= extMan
->extentList
.end(); it
++) {
214 asprintf(&result
, "%s[%lld, %lld] ", temp
, it
->blockAddr
, it
->numBlocks
);
221 int SimpleTestCase(off_t addAddr
, off_t addBlocks
, off_t removeAddr
, off_t removeBlocks
, const char *expectedResult
)
223 class ExtentManager extMan
;
224 const char *actualResult
;
227 extMan
.Init(512, 512, 512*999);
228 extMan
.AddBlockRangeExtent(addAddr
, addBlocks
);
229 extMan
.RemoveBlockRangeExtent(removeAddr
, removeBlocks
);
230 actualResult
= DebugDescription(&extMan
);
231 if (strcmp(actualResult
, expectedResult
))
234 "SimpleTestCase(%lld, %lld, %lld, %lld) failed.\n"
235 " Expected result: %s\n"
236 " Actual result: %s\n",
237 addAddr
, addBlocks
, removeAddr
, removeBlocks
,
238 expectedResult
, actualResult
);
241 free((void *)actualResult
);
249 class ExtentManager
*extMan
;
251 // Create an extent, and remove one contained inside,
252 // leaving the start and end of the original extent.
253 // Create: [xxxxxxxxxx]
255 failed
|= SimpleTestCase(10, 10, 12, 6, "[0, 0] [10, 2] [18, 2] [999, 0] ");
257 // Create an extent, and remove the whole extent.
258 // Create: [xxxxxxxxxx]
259 // Remove: [..........]
260 failed
|= SimpleTestCase(10, 10, 10, 10, "[0, 0] [999, 0] ");
262 // Create an extent, and remove the first part of the extent.
263 // Create: [xxxxxxxxxx]
265 failed
|= SimpleTestCase(10, 10, 10, 6, "[0, 0] [16, 4] [999, 0] ");
267 // Create an extent, and remove the last part of the extent.
268 // Create: [xxxxxxxxxx]
270 failed
|= SimpleTestCase(10, 10, 14, 6, "[0, 0] [10, 4] [999, 0] ");
272 // Create an extent and remove before the start, through the middle.
273 // Create: [xxxxxxxxxx]
274 // Remove: [..........]
275 failed
|= SimpleTestCase(10, 10, 6, 10, "[0, 0] [16, 4] [999, 0] ");
277 // Create an extent and remove from middle to past the end.
278 // Create: [xxxxxxxxxx]
279 // Remove: [..........]
280 failed
|= SimpleTestCase(10, 10, 14, 10, "[0, 0] [10, 4] [999, 0] ");
282 // Create an extent and remove from before through past end.
283 // Create: [xxxxxxxxxx]
284 // Remove: [..............]
285 failed
|= SimpleTestCase(10, 10, 6, 18, "[0, 0] [999, 0] ");
287 // Create an extent and remove purely before the extent.
288 // Create: [xxxxxxxxxx]
290 failed
|= SimpleTestCase(10, 10, 2, 5, "[0, 0] [10, 10] [999, 0] ");
292 // Create an extent and remove purely after the extent.
293 // Create: [xxxxxxxxxx]
295 failed
|= SimpleTestCase(10, 10, 22, 5, "[0, 0] [10, 10] [999, 0] ");
300 printf("Success.\n");
305 #endif /* UNIT_TEST */