1 package com.quadcap.sql.file; 2 3 40 41 import java.io.IOException ; 42 import java.io.InputStream ; 43 import java.io.OutputStream ; 44 45 import com.quadcap.util.ConfigNumber; 46 import com.quadcap.util.Debug; 47 import com.quadcap.util.Util; 48 49 56 public class SubPageManager implements PageManager { 57 BlockFile file; 58 62 long rootBlock; 63 64 65 int pageSize; 66 67 68 int pageShift; 69 70 71 int offset; 72 73 74 int pagesPerBlock; 75 76 static final long PAGE_FREE = 0xabcddbca5438182fL; 78 79 82 public SubPageManager(BlockFile file, int pageShift, long rootBlock) 83 throws IOException 84 { 85 this.file = file; 86 this.pageShift = pageShift; 87 this.rootBlock = rootBlock; 88 this.offset = BlockFile.oSUBPAGE_ROOT + pageShift * BlockFile.REF_SIZE; 89 this.pageSize = file.getPageSize() >> pageShift; 90 this.pagesPerBlock = 1 << pageShift; 91 if (pageSize < BlockFile.REF_SIZE * 2) { 92 throw new IOException ("Sub page too small: " + pageSize); 93 } 94 } 95 96 99 public long newPage() throws IOException { 100 long ret = -1; 101 synchronized (file.fileLock) { 102 Block root = file.getBlock(rootBlock); 103 Page page = null; 104 try { 105 ret = root.readLong(offset); 106 if (ret == 0) { 107 ret = allocateNewBlock(); 108 } 109 page = getPage(ret); 110 long next = page.readLong(0); 111 if (page.readLong(BlockFile.REF_SIZE) != PAGE_FREE) { 112 byte[] ff = new byte[pageSize]; 114 page.read(0, ff, 0, pageSize); 115 Debug.println("Page: " + Util.strBytes(ff)); 116 Debug.println("" + toString() + 117 ".newPage() " + 118 toString(ret) + 119 ", freelist corrupted: "); 120 throw new DatafileException("" + toString() + 122 ".newPage() " + 123 toString(ret) + 124 ", freelist corrupted: "); 125 126 } 127 root.writeLong(offset, next); 128 page.clear(); } finally { 130 if (page != null) page.decrRefCount(); 131 root.decrRefCount(); 132 } 133 if (Trace.bit(11)) { 135 Debug.println("" + toString() + ".newPage() = " + 136 toString(ret)); 137 } 138 if (pageShift(ret) != pageShift) { 139 throw new DatafileException("" + toString() + ".newPage(), " + 140 toString(ret) + 141 ", freelist corrupted"); 142 } 143 } 145 return ret; 146 } 147 148 153 public void freePage(long block) throws IOException { 154 if (Trace.bit(11)) { 159 Debug.println("" + toString() + ".freePage(" + 160 toString(block) + ")"); 161 } 162 if (pageShift(block) != pageShift) { 164 throw new DatafileException("" + toString() + ".freePage(" + 165 toString(block) + "), bad page"); 166 } 167 synchronized (file.fileLock) { 168 Block root = file.getBlock(rootBlock); 169 try { 170 long head = root.readLong(offset); 171 if (head == block) { 172 throw new DatafileException("" + toString() + ",freePage(" + 173 toString(block) + "), already" + 174 " free"); 175 } 176 Page page = getPage(block); 177 page.writeLong(0, head); 178 if (page.readLong(BlockFile.REF_SIZE) == PAGE_FREE) { 179 throw new DatafileException("" + toString() + ",freePage(" + 180 toString(block) + "), already" + 181 " free"); 182 } 183 page.writeLong(BlockFile.REF_SIZE, PAGE_FREE); 184 root.writeLong(offset, block); 185 page.decrRefCount(); 186 } finally { 187 root.decrRefCount(); 188 } 189 } 190 } 191 192 196 private final long allocateNewBlock() throws IOException { 197 long blk = file.newPage(); 198 if (Trace.bit(11)) { 200 Debug.println("" + toString() + ".allocateNewBlock: " + blk); 201 } 202 Block b = file.getBlock(blk); 204 b.writeLong(0, 0); 205 b.writeLong(BlockFile.REF_SIZE, PAGE_FREE); 206 try { 207 long p = makePageNo(blk, 0); 208 for (int i = 1; i < pagesPerBlock; i++) { 209 long np = makePageNo(blk, i); 210 Page page = getPage(np); 211 try { 212 page.writeLong(0, p); 213 page.writeLong(BlockFile.REF_SIZE, PAGE_FREE); 214 p = np; 215 } finally { 216 page.decrRefCount(); 217 } 218 } 219 return p; 220 } finally { 221 b.decrRefCount(); 222 } 223 } 224 225 239 240 static int[] PAGE_SHIFT = {63,4}; 241 static int[] PAGE_NUM = {59,16}; 242 static int[] BLOCK_NUM = {43,44}; 247 249 static final long fIns(long v, int[] f) { 250 return (v & fMask(f)) << fEnd(f); 251 } 252 static final long fMask(int[] f) { 253 return (1L << f[1]) - 1; 254 } 255 static final long fEnd(int[] f) { 256 return f[0] - f[1] + 1; 257 } 258 static final long fExt(long v, int[] f) { 259 return (v >> fEnd(f)) & fMask(f); 260 } 261 262 final long makePageNo(long blk, long page) { 263 long ret = fIns(pageShift, PAGE_SHIFT) 268 | fIns(page, PAGE_NUM) 272 | fIns(blk, BLOCK_NUM); 273 return ret; 286 } 287 288 291 public static final long pageBlock(long page) { 292 return fExt(page, BLOCK_NUM); 296 } 297 298 311 314 public final int pageOffset(long page) { 315 return (int)(fExt(page, PAGE_NUM) * pageSize); 319 } 320 321 324 static final int pageShift(long page) { 325 return (int)(fExt(page, PAGE_SHIFT)); 329 } 330 331 334 public Page getPage(long block) throws IOException { 335 return new SubPage(this, block); 339 } 340 341 344 public Object getLock() { return file.getLock(); } 345 346 349 public final int getPageSize() { 350 return pageSize; 351 } 352 353 362 public RandomAccessInputStream getInputStream(long block) 363 throws IOException 364 { 365 return new RandomAccessInputStream(getStream(block)); 366 } 367 368 377 public RandomAccessOutputStream getOutputStream(long block) 378 throws IOException 379 { 380 return new RandomAccessOutputStream(getStream(block)); 381 } 382 383 public RandomAccess getStream(long blockRef) throws IOException { 384 return new BlockAccess(this, blockRef); 385 } 386 387 396 public void freeStream(long page) throws IOException { 397 synchronized (file.fileLock) { 398 getStream(page).resize(0); 399 freePage(page); 400 } 401 } 402 403 407 public String toString() { 408 return "PM" + pageSize + ":[" + rootBlock + "," + offset + "]"; 409 } 410 412 public static String toString(long page) { 413 int psize = 8192 >> pageShift(page); 414 long pnum = fExt(page, PAGE_NUM); 415 return "Page(" + psize + 416 ")[" + pageBlock(page) + 417 ":" + pnum + " (" + (pnum * psize) + ")" + 418 ']'; 419 } 420 } 421 | Popular Tags |