00001
package com.quadcap.sql.file;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.IOException;
00042
import java.io.InputStream;
00043
import java.io.OutputStream;
00044
00045
import com.quadcap.util.ConfigNumber;
00046
import com.quadcap.util.Debug;
00047
import com.quadcap.util.Util;
00048
00049
00050
00051
00052
00053
00054
00055
00056 public class SubPageManager implements PageManager {
00057 BlockFile file;
00058
00059
00060
00061
00062 long rootBlock;
00063
00064
00065 int pageSize;
00066
00067
00068 int pageShift;
00069
00070
00071 int offset;
00072
00073
00074 int pagesPerBlock;
00075
00076
00077 static final long PAGE_FREE = 0xabcddbca5438182fL;
00078
00079
00080
00081
00082 public SubPageManager(
BlockFile file,
int pageShift,
long rootBlock)
00083
throws IOException
00084 {
00085
this.file =
file;
00086
this.pageShift =
pageShift;
00087
this.rootBlock =
rootBlock;
00088
this.offset =
BlockFile.oSUBPAGE_ROOT +
pageShift *
BlockFile.REF_SIZE;
00089
this.pageSize =
file.
getPageSize() >>
pageShift;
00090
this.pagesPerBlock = 1 <<
pageShift;
00091
if (
pageSize <
BlockFile.REF_SIZE * 2) {
00092
throw new IOException(
"Sub page too small: " +
pageSize);
00093 }
00094 }
00095
00096
00097
00098
00099 public long newPage() throws IOException {
00100
long ret = -1;
00101
synchronized (
file.
fileLock) {
00102
Block root =
file.
getBlock(
rootBlock);
00103
Page page = null;
00104
try {
00105 ret = root.
readLong(
offset);
00106
if (ret == 0) {
00107 ret =
allocateNewBlock();
00108 }
00109 page =
getPage(ret);
00110
long next = page.
readLong(0);
00111
if (page.
readLong(
BlockFile.REF_SIZE) !=
PAGE_FREE) {
00112
00113 byte[] ff =
new byte[
pageSize];
00114 page.
read(0, ff, 0,
pageSize);
00115
Debug.println(
"Page: " +
Util.strBytes(ff));
00116
Debug.println(
"" +
toString() +
00117
".newPage() " +
00118
toString(ret) +
00119
", freelist corrupted: ");
00120
00121
throw new DatafileException(
"" +
toString() +
00122
".newPage() " +
00123
toString(ret) +
00124
", freelist corrupted: ");
00125
00126 }
00127 root.
writeLong(
offset, next);
00128 page.
clear();
00129 } finally {
00130
if (page != null) page.
decrRefCount();
00131 root.
decrRefCount();
00132 }
00133
00134
if (
Trace.bit(11)) {
00135
Debug.println(
"" +
toString() +
".newPage() = " +
00136
toString(ret));
00137 }
00138
if (
pageShift(ret) !=
pageShift) {
00139
throw new DatafileException(
"" +
toString() +
".newPage(), " +
00140
toString(ret) +
00141
", freelist corrupted");
00142 }
00143
00144 }
00145
return ret;
00146 }
00147
00148
00149
00150
00151
00152
00153 public void freePage(
long block)
throws IOException {
00154
00155
00156
00157
00158
if (
Trace.bit(11)) {
00159
Debug.println(
"" +
toString() +
".freePage(" +
00160
toString(block) +
")");
00161 }
00162
00163
if (
pageShift(block) !=
pageShift) {
00164
throw new DatafileException(
"" +
toString() +
".freePage(" +
00165
toString(block) +
"), bad page");
00166 }
00167
synchronized (
file.
fileLock) {
00168
Block root =
file.
getBlock(
rootBlock);
00169
try {
00170
long head = root.
readLong(
offset);
00171
if (head == block) {
00172
throw new DatafileException(
"" +
toString() +
",freePage(" +
00173
toString(block) +
"), already" +
00174
" free");
00175 }
00176
Page page =
getPage(block);
00177 page.
writeLong(0, head);
00178
if (page.
readLong(
BlockFile.REF_SIZE) ==
PAGE_FREE) {
00179
throw new DatafileException(
"" +
toString() +
",freePage(" +
00180
toString(block) +
"), already" +
00181
" free");
00182 }
00183 page.
writeLong(
BlockFile.REF_SIZE,
PAGE_FREE);
00184 root.
writeLong(
offset, block);
00185 page.
decrRefCount();
00186 } finally {
00187 root.
decrRefCount();
00188 }
00189 }
00190 }
00191
00192
00193
00194
00195
00196 private final long allocateNewBlock() throws IOException {
00197
long blk =
file.
newPage();
00198
00199
if (
Trace.bit(11)) {
00200
Debug.println(
"" +
toString() +
".allocateNewBlock: " + blk);
00201 }
00202
00203
Block b =
file.
getBlock(blk);
00204 b.
writeLong(0, 0);
00205 b.
writeLong(
BlockFile.REF_SIZE,
PAGE_FREE);
00206
try {
00207
long p =
makePageNo(blk, 0);
00208
for (
int i = 1; i <
pagesPerBlock; i++) {
00209
long np = makePageNo(blk, i);
00210
Page page =
getPage(np);
00211
try {
00212 page.
writeLong(0, p);
00213 page.
writeLong(
BlockFile.REF_SIZE,
PAGE_FREE);
00214 p = np;
00215 } finally {
00216 page.
decrRefCount();
00217 }
00218 }
00219
return p;
00220 } finally {
00221 b.
decrRefCount();
00222 }
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 static int[]
PAGE_SHIFT = {63,4};
00241 static int[]
PAGE_NUM = {59,16};
00242
00243
00244
00245
00246 static int[]
BLOCK_NUM = {43,44};
00247
00248
00249 static final long fIns(
long v,
int[] f) {
00250
return (v &
fMask(f)) <<
fEnd(f);
00251 }
00252 static final long fMask(
int[] f) {
00253
return (1L << f[1]) - 1;
00254 }
00255 static final long fEnd(
int[] f) {
00256
return f[0] - f[1] + 1;
00257 }
00258 static final long fExt(
long v,
int[] f) {
00259
return (v >> fEnd(f)) & fMask(f);
00260 }
00261
00262 final long makePageNo(
long blk,
long page) {
00263
00264
00265
00266
00267
long ret = fIns(
pageShift,
PAGE_SHIFT)
00268
00269
00270
00271 | fIns(page,
PAGE_NUM)
00272 | fIns(blk,
BLOCK_NUM);
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
return ret;
00286 }
00287
00288
00289
00290
00291 public static final long pageBlock(
long page) {
00292
00293
00294
00295
return fExt(page,
BLOCK_NUM);
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 public final int pageOffset(
long page) {
00315
00316
00317
00318
return (
int)(fExt(page,
PAGE_NUM) *
pageSize);
00319 }
00320
00321
00322
00323
00324 static final int pageShift(
long page) {
00325
00326
00327
00328
return (
int)(fExt(page,
PAGE_SHIFT));
00329 }
00330
00331
00332
00333
00334 public Page getPage(
long block)
throws IOException {
00335
00336
00337
00338
return new SubPage(
this, block);
00339 }
00340
00341
00342
00343
00344 public Object
getLock() {
return file.
getLock(); }
00345
00346
00347
00348
00349 public final int getPageSize() {
00350
return pageSize;
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 public RandomAccessInputStream getInputStream(
long block)
00363
throws IOException
00364 {
00365
return new RandomAccessInputStream(
getStream(block));
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 public RandomAccessOutputStream getOutputStream(
long block)
00378
throws IOException
00379 {
00380
return new RandomAccessOutputStream(
getStream(block));
00381 }
00382
00383 public RandomAccess getStream(
long blockRef)
throws IOException {
00384
return new BlockAccess(
this, blockRef);
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 public void freeStream(
long page)
throws IOException {
00397
synchronized (
file.
fileLock) {
00398 getStream(page).
resize(0);
00399 freePage(page);
00400 }
00401 }
00402
00403
00404
00405
00406
00407 public String
toString() {
00408
return "PM" +
pageSize +
":[" +
rootBlock +
"," +
offset +
"]";
00409 }
00410
00411
00412 public static String
toString(
long page) {
00413
int psize = 8192 >> pageShift(page);
00414
long pnum = fExt(page,
PAGE_NUM);
00415
return "Page(" + psize +
00416
")[" + pageBlock(page) +
00417
":" + pnum +
" (" + (pnum * psize) +
")" +
00418
']';
00419 }
00420 }