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
00043
import com.quadcap.util.ConfigNumber;
00044
import com.quadcap.util.Debug;
00045
import com.quadcap.util.Util;
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 public class BlockAccess extends RandomAccess {
00059 static final int HEADER_SIZE = 8;
00060 static final int REF_SIZE = 8;
00061
00062
00063
00064
00065 PageManager file;
00066
00067
00068
00069
00070
00071
00072 long rootBlock;
00073 long size;
00074
00075
00076
00077
00078
00079 int[]
radices = null;
00080
00081 byte[]
b1 =
new byte[1];
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 int depth = 0;
00092
00093
00094
00095
00096 BlockPath path = null;
00097
00098
00099
00100
00101 Object
fileLock = null;
00102
00103
00104
00105
00106 public BlockAccess() {}
00107
00108
00109
00110
00111
00112 public BlockAccess(
PageManager file,
long rootBlock)
throws IOException {
00113
init(
file,
rootBlock);
00114 }
00115
00116 public void init(
PageManager file,
long rootBlock)
throws IOException {
00117
this.file =
file;
00118
this.fileLock =
file.
getLock();
00119
this.rootBlock =
rootBlock;
00120
this.path = null;
00121
00122
synchronized (
fileLock) {
00123
Page root =
file.
getPage(
rootBlock);
00124
try {
00125
this.size = root.
readLong(0);
00126
00127
if (
Trace.bit(3)) {
00128
Debug.println(
"INIT: " +
this);
00129 }
00130
00131 } finally {
00132 root.
decrRefCount();
00133 }
00134 }
00135
this.depth =
depthForSize(
this.
size);
00136
this.radices =
radicesForDepth(
this.
depth);
00137 }
00138
00139
00140
00141
00142 public long size() {
00143
return this.size;
00144 }
00145
00146
00147
00148
00149 public void resize(
long newSize)
throws IOException {
00150
00151
if (
Trace.bit(2)) {
00152
Debug.println(
"BlockAccess[" +
toString(
rootBlock) +
":" + size +
00153
"] resize(" + newSize +
")");
00154 }
00155
00156
synchronized (
fileLock) {
00157
Page root =
file.
getPage(
rootBlock);
00158
try {
00159
long curSize = root.
readLong(0);
00160 byte[] bufx =
new byte[
bufLen()];
00161
int rsize = bufx.length -
HEADER_SIZE;
00162
this.size = newSize;
00163
00164
int newDepth =
depthForSize(newSize);
00165
while (newDepth >
depth) {
00166
00167
long newPage =
file.
newPage();
00168
Page b =
file.
getPage(newPage);
00169
try {
00170 root.
read(
HEADER_SIZE, bufx, 0, rsize);
00171 root.
clear();
00172 b.
write(0, bufx, 0, rsize);
00173
setBlockRef(root, 0, newPage,
true);
00174
radices =
radicesForDepth(++
depth);
00175 } finally {
00176 b.
decrRefCount();
00177 }
00178 }
00179
00180
while (newDepth <
depth) {
00181
00182
for (
int i = 1; i <
refsForLevel(0); i++) {
00183
long blk =
getBlockRef(root, i,
true);
00184
if (blk != 0) {
00185
file.
freePage(blk);
00186
setBlockRef(root, i, 0,
true);
00187 }
00188 }
00189
long freePage =
getBlockRef(root, 0,
true);
00190
Page b =
file.
getPage(freePage);
00191
try {
00192 b.
read(0, bufx, 0, rsize);
00193 root.
write(
HEADER_SIZE, bufx, 0, rsize);
00194
radices =
radicesForDepth(--
depth);
00195 } finally {
00196 b.
decrRefCount();
00197 }
00198
file.
freePage(freePage);
00199 }
00200 root.
writeLong(0, newSize);
00201 } finally {
00202 root.
decrRefCount();
00203 }
00204 }
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 public void write(
long pos, byte[] buf,
int offset,
int len)
00216
throws IOException
00217 {
00218
synchronized (
fileLock) {
00219
00220
if (
Trace.bit(2)) {
00221
Debug.println(
"[" +
toString(
rootBlock) +
":" + size +
00222
"] write(" +
00223 pos +
", " +
Util.strBytes(buf, offset, len) +
")");
00224 }
00225
00226
Page root =
file.
getPage(
rootBlock);
00227
try {
00228
BlockPath p =
getPath(pos);
00229
int hdr = (
depth >= 1) ? 0 :
HEADER_SIZE;
00230
while (len > 0) {
00231
int bufloc = p.
getBufPos();
00232
int amt = Math.min(len, (
bufLen() - hdr) - bufloc);
00233
Page b = p.
getLeafBlock();
00234
try {
00235 b.
write(bufloc + hdr, buf, offset, amt);
00236 } finally {
00237 b.
decrRefCount();
00238 }
00239 len -= amt;
00240 offset += amt;
00241
00242
00243
if (len > 0) p.
incr(amt);
00244 }
00245 } finally {
00246 root.
decrRefCount();
00247 }
00248 }
00249 }
00250
00251
00252
00253
00254 public void read(
long pos, byte[] buf,
int offset,
int len)
00255
throws IOException
00256 {
00257
00258
if (pos + len > size) {
00259
throw new IOException(
"BlockAccess.read() out of bounds: " +
00260
"pos = " + pos +
00261
", len = " + len +
00262
", size = " +
size());
00263 }
00264
long save_pos = pos;
00265
int save_offset = offset;
00266
int save_len = len;
00267
00268
00269
synchronized (
fileLock) {
00270
Page root =
file.
getPage(
rootBlock);
00271
try {
00272
BlockPath p =
getPath(pos);
00273
int hdr = (
depth >= 1) ? 0 :
HEADER_SIZE;
00274
while (len > 0) {
00275
int bufloc = p.
getBufPos();
00276
int amt = Math.min(len, (
bufLen() - hdr) - bufloc);
00277
00278
if (amt <= 0) {
00279
Debug.println(
"pos = " + pos +
", offset = " + offset +
00280
", len = " + len +
", bufloc = " + bufloc +
00281
", bufLen() = " +
bufLen());
00282
Debug.println(
"save_pos = " + save_pos +
00283
", save_offset = " + save_offset +
00284
", save_len = " + save_len);
00285
Debug.println(
"p = " + p);
00286
Debug.println(
"size = " + size);
00287
Debug.println(
"depth = " + depth);
00288
for (
int i = 0; i <
radices.length; i++) {
00289
Debug.println(
"radix[" + i +
"] = " +
radices[i]);
00290 }
00291
throw new RuntimeException(
"Internal error: amt: " + amt);
00292 }
00293
00294
Page b = p.
getLeafBlock();
00295
try {
00296 b.
read(bufloc + hdr, buf, offset, amt);
00297 } finally {
00298 b.
decrRefCount();
00299 }
00300 len -= amt;
00301 offset += amt;
00302
00303
if (len > 0) p.
incr(amt);
00304 }
00305 } finally {
00306 root.
decrRefCount();
00307 }
00308 }
00309 }
00310
00311
00312
00313
00314 public void close() {
00315 }
00316
00317 public void flush() {
00318 }
00319
00320 private final BlockPath getPath(
long pos)
throws IOException {
00321
if (
path == null ||
depth !=
path.
getDepth()) {
00322
path =
new BlockPath(
this, pos);
00323 }
else {
00324
path.
setPos(pos);
00325 }
00326
return path;
00327 }
00328
00329
00330
00331
00332 final int[]
radicesForDepth(
int depth) {
00333
int[] v =
new int[depth];
00334
int r =
bufLen();
00335
for (
int i = depth-1; i >= 0; i--) {
00336 v[i] = r;
00337 r *=
refsForLevel(i);
00338 }
00339
return v;
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 final long getBlockRef(
Page b,
int pos,
boolean isRoot)
00351
throws IOException
00352 {
00353
int offset = pos *
REF_SIZE + (isRoot ?
HEADER_SIZE : 0);
00354
long ref = b.readLong(offset);
00355
return ref;
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 final long makeBlockRef(
Page b,
int pos,
boolean isRoot)
00370
throws IOException
00371 {
00372
int offset = pos *
REF_SIZE + (isRoot ?
HEADER_SIZE : 0);
00373
long ref = b.readLong(offset);
00374
if (ref == 0) {
00375 ref =
file.
newPage();
00376 b.writeLong(offset, ref);
00377 }
00378
return ref;
00379 }
00380
00381
00382
00383
00384
00385
00386
00387
00388 final void setBlockRef(
Page b,
int pos,
long val,
boolean isRoot) {
00389
int offset = pos *
REF_SIZE + (isRoot ?
HEADER_SIZE : 0);
00390 b.
writeLong(offset, val);
00391 }
00392
00393
00394
00395
00396 final int refsForLevel(
int level) {
00397
return (
bufLen() - (level == 0 ?
HEADER_SIZE : 0)) /
REF_SIZE;
00398 }
00399
00400
00401
00402
00403 final int bufLen() {
00404
return file.
getPageSize();
00405 }
00406
00407
00408
00409
00410 private final long maxSizeForDepth(
int level) {
00411
if (level == 0) {
00412
return bufLen() -
HEADER_SIZE;
00413 }
00414
long ret =
bufLen();
00415
for (
int i = 0; i < level; i++) {
00416 ret *= refsForLevel(i);
00417 }
00418
return ret;
00419 }
00420
00421
00422
00423
00424
00425
00426 private final int depthForSize(
long size) {
00427
if (size <=
bufLen() -
HEADER_SIZE)
return 0;
00428
00429
int ret = 1;
00430
long max =
bufLen() * refsForLevel(0);
00431
00432
while (size > max) {
00433 max *= refsForLevel(++ret);
00434 }
00435
return ret;
00436 }
00437
00438
00439 final String
toString(
long page) {
00440
return SubPageManager.toString(page);
00441 }
00442
00443 public String
toString() {
00444 StringBuffer sb =
new StringBuffer(
"BlockAccess(");
00445 sb.append(
"root=");
00446 sb.append(
SubPageManager.toString(
rootBlock));
00447 sb.append(
" size=");
00448 sb.append(size);
00449
if (
radices != null) {
00450 sb.append(
" radices=");
00451
for (
int i = 0; i <
radices.length; i++) {
00452
if (i>0) sb.append(
',');
00453 sb.append(
radices[i]);
00454 }
00455 }
00456 sb.append(
" depth=");
00457 sb.append(
depth);
00458 sb.append(
" path=");
00459 sb.append(
path);
00460 sb.append(
")");
00461
return sb.toString();
00462 }
00463
00464 }