1 29 30 package com.caucho.db.store; 31 32 import com.caucho.util.L10N; 33 import com.caucho.util.Log; 34 import com.caucho.vfs.OutputStreamWithBuffer; 35 import com.caucho.vfs.TempCharBuffer; 36 37 import java.io.IOException ; 38 import java.io.InputStream ; 39 import java.io.OutputStream ; 40 import java.io.Reader ; 41 import java.io.Writer ; 42 import java.util.logging.Level ; 43 import java.util.logging.Logger ; 44 45 64 public class Inode { 65 private static final L10N L = new L10N(Inode.class); 66 private static final Logger log = Log.open(Inode.class); 67 68 public static final int INODE_SIZE = 128; 69 public static final int INLINE_BLOB_SIZE = 120; 70 public static final int INODE_BLOCK_SIZE = Store.FRAGMENT_SIZE; 71 72 public static final int INDIRECT_BLOCKS = INODE_BLOCK_SIZE / 8; 73 74 public static final int DIRECT_BLOCKS = 14; 76 public static final int SINGLE_INDIRECT_BLOCKS = 512; 78 public static final int DOUBLE_INDIRECT_BLOCKS = 128; 80 public static final int TRIPLE_INDIRECT_BLOCKS = 128; 82 public static final int QUAD_INDIRECT_BLOCKS = 128; 84 public static final int PENTA_INDIRECT_BLOCKS = 128; 86 87 private static final byte []NULL_BYTES = new byte[INODE_SIZE]; 88 89 private Store _store; 90 private StoreTransaction _xa; 91 92 private byte []_bytes = new byte[INODE_SIZE]; 93 94 public Inode() 95 { 96 } 97 98 public Inode(Store store, StoreTransaction xa) 99 { 100 _store = store; 101 _xa = xa; 102 } 103 104 public Inode(Store store) 105 { 106 this(store, RawTransaction.create()); 107 } 108 109 112 public Store getStore() 113 { 114 return _store; 115 } 116 117 120 public byte []getBuffer() 121 { 122 return _bytes; 123 } 124 125 128 public long getLength() 129 { 130 return readLong(_bytes, 0); 131 } 132 133 public void init(Store store, StoreTransaction xa, 134 byte []buffer, int offset) 135 { 136 _store = store; 137 _xa = xa; 138 139 System.arraycopy(buffer, offset, _bytes, 0, _bytes.length); 140 } 141 142 145 public InputStream openInputStream() 146 { 147 return new BlobInputStream(this); 148 } 149 150 153 public void writeToStream(OutputStreamWithBuffer os) 154 throws IOException 155 { 156 writeToStream(os, 0, Long.MAX_VALUE / 2); 157 } 158 159 162 public void writeToStream(OutputStreamWithBuffer os, 163 long offset, long length) 164 throws IOException 165 { 166 byte []buffer = os.getBuffer(); 167 int writeLength = buffer.length; 168 int writeOffset = os.getBufferOffset(); 169 170 while (length > 0) { 171 int sublen = writeLength - writeOffset; 172 173 if (sublen == 0) { 174 buffer = os.nextBuffer(writeOffset); 175 writeOffset = os.getBufferOffset(); 176 sublen = writeLength - writeOffset; 177 } 178 179 if (length < sublen) 180 sublen = (int) length; 181 182 int len = read(_bytes, 0, _store, 183 offset, 184 buffer, writeOffset, sublen); 185 186 if (len <= 0) 187 break; 188 189 writeOffset += len; 190 offset += len; 191 length -= len; 192 } 193 194 os.setBufferOffset(writeOffset); 195 } 196 197 200 public void writeToWriter(Writer writer) 201 throws IOException 202 { 203 TempCharBuffer tempBuffer = TempCharBuffer.allocate(); 204 205 char []buffer = tempBuffer.getBuffer(); 206 int writeLength = buffer.length; 207 long offset = 0; 208 209 while (true) { 210 int sublen = writeLength; 211 212 int len = read(_bytes, 0, _store, 213 offset, 214 buffer, 0, sublen); 215 216 if (len <= 0) 217 break; 218 219 writer.write(buffer, 0, len); 220 221 offset += 2 * len; 222 } 223 224 TempCharBuffer.free(tempBuffer); 225 } 226 227 240 static int read(byte []inode, int inodeOffset, 241 Store store, 242 long fileOffset, 243 byte []buffer, int bufferOffset, int bufferLength) 244 throws IOException 245 { 246 long fileLength = readLong(inode, inodeOffset); 247 248 int sublen = bufferLength; 249 if (fileLength - fileOffset < sublen) 250 sublen = (int) (fileLength - fileOffset); 251 252 if (sublen <= 0) 253 return -1; 254 255 if (fileLength <= Inode.INLINE_BLOB_SIZE) { 256 System.arraycopy(inode, inodeOffset + 8 + (int) fileOffset, 257 buffer, bufferOffset, sublen); 258 259 return sublen; 260 } 261 262 long fragAddr = readFragmentAddr(inode, inodeOffset, store, fileOffset); 263 int fragOffset = (int) (fileOffset % Inode.INODE_BLOCK_SIZE); 264 265 if (INODE_BLOCK_SIZE - fragOffset < sublen) 266 sublen = INODE_BLOCK_SIZE - fragOffset; 267 268 store.readFragment(fragAddr, fragOffset, buffer, bufferOffset, sublen); 269 270 return sublen; 271 } 272 273 276 static void append(byte []inode, int inodeOffset, 277 Store store, StoreTransaction xa, 278 byte []buffer, int offset, int length) 279 throws IOException 280 { 281 long currentLength = readLong(inode, inodeOffset); 282 long newLength = currentLength + length; 283 284 writeLong(inode, inodeOffset, newLength); 285 286 if (newLength <= INLINE_BLOB_SIZE) { 287 System.arraycopy(buffer, offset, 288 inode, (int) (inodeOffset + 8 + currentLength), 289 length); 290 } 291 else { 292 295 if (currentLength % INODE_BLOCK_SIZE != 0) { 296 long fragAddr = readFragmentAddr(inode, inodeOffset, 297 store, 298 currentLength); 299 300 if (fragAddr == 0) 301 throw new IllegalStateException ("inode: illegal fragment at " + currentLength); 302 303 int fragOffset = (int) (currentLength % INODE_BLOCK_SIZE); 304 int sublen = length; 305 306 if (INODE_BLOCK_SIZE - fragOffset < sublen) 307 sublen = INODE_BLOCK_SIZE - fragOffset; 308 309 store.writeFragment(xa, fragAddr, fragOffset, buffer, offset, sublen); 310 311 offset += sublen; 312 length -= sublen; 313 314 currentLength += sublen; 315 } 316 317 while (length > 0) { 318 int sublen = length; 319 320 if (INODE_BLOCK_SIZE < sublen) 321 sublen = INODE_BLOCK_SIZE; 322 323 long fragAddr = store.allocateFragment(xa); 324 325 if (fragAddr == 0) 326 throw new IllegalStateException (L.l("illegal fragment")); 327 328 writeFragmentAddr(inode, inodeOffset, 329 store, xa, 330 currentLength, fragAddr); 331 332 store.writeFragment(xa, fragAddr, 0, buffer, offset, sublen); 333 334 offset += sublen; 335 length -= sublen; 336 337 currentLength += sublen; 338 } 339 } 340 } 341 342 355 static int read(byte []inode, int inodeOffset, Store store, 356 long fileOffset, 357 char []buffer, int bufferOffset, int bufferLength) 358 throws IOException 359 { 360 long fileLength = readLong(inode, inodeOffset); 361 362 int sublen = (int) (fileLength - fileOffset) / 2; 363 if (bufferLength < sublen) 364 sublen = bufferLength; 365 366 if (sublen <= 0) 367 return -1; 368 369 if (fileLength <= Inode.INLINE_BLOB_SIZE) { 370 int baseOffset = inodeOffset + 8 + (int) fileOffset; 371 372 for (int i = 0; i < sublen; i++) { 373 char ch = (char) (((inode[baseOffset] & 0xff) << 8) + 374 ((inode[baseOffset + 1] & 0xff))); 375 376 buffer[bufferOffset + i] = ch; 377 378 baseOffset += 2; 379 } 380 381 return sublen; 382 } 383 384 long fragAddr = readFragmentAddr(inode, inodeOffset, store, fileOffset); 385 int fragOffset = (int) (fileOffset % Inode.INODE_BLOCK_SIZE); 386 387 if (INODE_BLOCK_SIZE - fragOffset < 2 * sublen) 388 sublen = (INODE_BLOCK_SIZE - fragOffset) / 2; 389 390 store.readFragment(fragAddr, fragOffset, buffer, bufferOffset, sublen); 391 392 return sublen; 393 } 394 395 398 static void append(byte []inode, int inodeOffset, 399 Store store, StoreTransaction xa, 400 char []buffer, int offset, int length) 401 throws IOException 402 { 403 long currentLength = readLong(inode, inodeOffset); 404 long newLength = currentLength + length; 405 406 writeLong(inode, inodeOffset, newLength); 407 408 if (newLength <= INLINE_BLOB_SIZE) { 409 int writeOffset = (int) (inodeOffset + 8 + currentLength); 410 411 for (int i = 0; i < length; i++) { 412 char ch = buffer[offset + i]; 413 414 inode[writeOffset++] = (byte) (ch >> 8); 415 inode[writeOffset++] = (byte) (ch); 416 } 417 } 418 else { 419 422 if (currentLength % INODE_BLOCK_SIZE != 0) { 423 long fragAddr = readFragmentAddr(inode, inodeOffset, 424 store, 425 currentLength); 426 427 int fragOffset = (int) (currentLength % INODE_BLOCK_SIZE); 428 int sublen = 2 * length; 429 430 if (INODE_BLOCK_SIZE - fragOffset < sublen) 431 sublen = INODE_BLOCK_SIZE - fragOffset; 432 433 store.writeFragment(xa, fragAddr, fragOffset, buffer, offset, sublen); 434 435 offset += sublen / 2; 436 length -= sublen / 2; 437 438 currentLength += sublen; 439 } 440 441 while (length > 0) { 442 int sublen = 2 * length; 443 444 if (INODE_BLOCK_SIZE < sublen) 445 sublen = INODE_BLOCK_SIZE; 446 447 long fragAddr = store.allocateFragment(xa); 448 449 writeFragmentAddr(inode, inodeOffset, 450 store, xa, 451 currentLength, fragAddr); 452 453 store.writeFragment(xa, fragAddr, 0, buffer, offset, sublen); 454 455 offset += sublen / 2; 456 length -= sublen / 2; 457 458 currentLength += sublen; 459 } 460 } 461 } 462 463 466 public OutputStream openOutputStream() 467 { 468 return new BlobOutputStream(this); 469 } 470 471 474 void closeOutputStream() 475 { 476 try { 477 _store.saveAllocation(); 478 } catch (Throwable e) { 479 log.log(Level.FINER, e.toString(), e); 480 } 481 } 482 483 486 public Reader openReader() 487 { 488 return new ClobReader(this); 489 } 490 491 494 public Writer openWriter() 495 { 496 return new ClobWriter(this); 497 } 498 499 502 public void remove() 503 { 504 synchronized (_bytes) { 505 long length = readLong(_bytes, 0); 506 507 byte []bytes = _bytes; 508 509 try { 510 if (length <= INLINE_BLOB_SIZE || bytes == null) 511 return; 512 513 long initLength = length; 514 for (; length > 0; length -= INODE_BLOCK_SIZE) { 515 long fragAddr = readFragmentAddr(bytes, 0, _store, length - 1); 516 517 if ((fragAddr & Store.BLOCK_MASK) == 0) { 518 String msg = _store + ": inode block " + Long.toHexString(length) + " has 0 fragment"; 519 throw stateError(msg); 520 } 521 else if (fragAddr < 0) { 522 String msg = _store + ": inode block " + Long.toHexString(length) + " has invalid fragment " + Long.toHexString(fragAddr); 523 524 throw stateError(msg); 525 } 526 527 _store.deleteFragment(_xa, fragAddr); 528 529 int fragCount = (int) ((length - 1) / INODE_BLOCK_SIZE); 530 531 int dblFragCount = fragCount - DIRECT_BLOCKS - SINGLE_INDIRECT_BLOCKS; 532 533 if (dblFragCount >= 0 && 535 dblFragCount % INDIRECT_BLOCKS == 0) { 536 fragAddr = readLong(bytes, (DIRECT_BLOCKS + 1) * 8); 537 538 int dblIndex = (int) (fragCount / INDIRECT_BLOCKS); 539 540 fragAddr = _store.readFragmentLong(fragAddr, dblIndex); 541 542 if (fragAddr != 0) 543 _store.deleteFragment(_xa, fragAddr); 544 } 545 546 if (fragCount == DIRECT_BLOCKS) { 548 fragAddr = readLong(bytes, (DIRECT_BLOCKS + 1) * 8); 549 550 if (fragAddr != 0) { 551 _store.deleteFragment(_xa, fragAddr); 552 } 553 } 554 } 555 } catch (Throwable e) { 556 log.log(Level.WARNING, e.toString(), e); 557 } finally { 558 System.arraycopy(NULL_BYTES, 0, _bytes, 0, NULL_BYTES.length); 559 560 try { 561 _store.saveAllocation(); 562 } catch (Throwable e) { 563 log.log(Level.FINE, e.toString(), e); 564 } 565 } 566 } 567 } 568 569 572 static void clear(byte []inode, int inodeOffset) 573 { 574 int end = inodeOffset + INODE_SIZE; 575 576 for (; inodeOffset < end; inodeOffset++) 577 inode[inodeOffset] = 0; 578 } 579 580 583 static long readFragmentAddr(byte []inode, int inodeOffset, 584 Store store, 585 long fileOffset) 586 throws IOException 587 { 588 long fragCount = fileOffset / INODE_BLOCK_SIZE; 589 590 if (fragCount < DIRECT_BLOCKS) 591 return readLong(inode, (int) (inodeOffset + 8 * (1 + fragCount))); 592 else if (fragCount < DIRECT_BLOCKS + SINGLE_INDIRECT_BLOCKS) { 593 long indirectAddr; 594 indirectAddr = readLong(inode, inodeOffset + (DIRECT_BLOCKS + 1) * 8); 595 596 if (indirectAddr == 0) 597 throw new IllegalStateException (L.l("null block id")); 598 599 int offset = (int) (8 * (fragCount - DIRECT_BLOCKS)); 600 601 long fragAddr = store.readFragmentLong(indirectAddr, offset); 602 603 return fragAddr; 604 } 605 else if (fragCount < (DIRECT_BLOCKS + 606 SINGLE_INDIRECT_BLOCKS + 607 DOUBLE_INDIRECT_BLOCKS * INDIRECT_BLOCKS)) { 608 long indirectAddr; 609 indirectAddr = readLong(inode, inodeOffset + (DIRECT_BLOCKS + 1) * 8); 610 611 if (indirectAddr == 0) 612 throw new IllegalStateException (L.l("null block id")); 613 614 fragCount -= DIRECT_BLOCKS + SINGLE_INDIRECT_BLOCKS; 615 616 int index = (int) (fragCount / INDIRECT_BLOCKS); 617 618 long doubleIndirectAddr = store.readFragmentLong(indirectAddr, index); 619 620 int offset = (int) (8 * (fragCount % INDIRECT_BLOCKS)); 621 622 return store.readFragmentLong(doubleIndirectAddr, offset); 623 } 624 else 625 throw new IllegalStateException (L.l("Can't yet support data over 64M")); 626 } 627 628 631 private static void writeFragmentAddr(byte []inode, int offset, 632 Store store, StoreTransaction xa, 633 long fragLength, long fragAddr) 634 throws IOException 635 { 636 int fragCount = (int) (fragLength / Store.FRAGMENT_SIZE); 637 638 if ((fragAddr & Store.BLOCK_MASK) == 0) { 640 String msg = store + ": inode block " + fragCount + " writing 0 fragment"; 641 throw stateError(msg); 642 } 643 644 if (fragCount < DIRECT_BLOCKS) { 645 writeLong(inode, offset + (fragCount + 1) * 8, fragAddr); 646 } 647 else if (fragCount < DIRECT_BLOCKS + SINGLE_INDIRECT_BLOCKS) { 648 long indAddr = readLong(inode, offset + (DIRECT_BLOCKS + 1) * 8); 649 650 if (indAddr == 0) { 651 indAddr = store.allocateFragment(xa); 652 653 writeLong(inode, offset + (DIRECT_BLOCKS + 1) * 8, indAddr); 654 } 655 656 int fragOffset = 8 * (fragCount - DIRECT_BLOCKS); 657 658 store.writeFragmentLong(xa, indAddr, fragOffset, fragAddr); 659 } 660 else if (fragCount < (DIRECT_BLOCKS + 661 SINGLE_INDIRECT_BLOCKS + 662 DOUBLE_INDIRECT_BLOCKS * INDIRECT_BLOCKS)) { 663 long indAddr = readLong(inode, offset + (DIRECT_BLOCKS + 1) * 8); 664 665 if (indAddr == 0) { 666 indAddr = store.allocateFragment(xa); 667 668 writeLong(inode, offset + (DIRECT_BLOCKS + 1) * 8, indAddr); 669 } 670 671 int count = fragCount - DIRECT_BLOCKS - SINGLE_INDIRECT_BLOCKS; 672 673 int dblIndCount = count / INDIRECT_BLOCKS; 674 675 long dblIndAddr = store.readFragmentLong(indAddr, dblIndCount * 8); 676 677 if (dblIndAddr == 0) { 678 dblIndAddr = store.allocateFragment(xa); 679 680 store.writeFragmentLong(xa, indAddr, dblIndCount * 8, dblIndAddr); 681 } 682 683 int fragOffset = 8 * (count % INDIRECT_BLOCKS); 684 685 store.writeFragmentLong(xa, dblIndAddr, fragOffset, fragAddr); 686 } 687 else 688 throw new IllegalStateException (L.l("Can't yet support data over 64M")); 689 } 690 691 694 public static long readLong(byte []buffer, int offset) 695 { 696 return (((buffer[offset + 0] & 0xffL) << 56) + 697 ((buffer[offset + 1] & 0xffL) << 48) + 698 ((buffer[offset + 2] & 0xffL) << 40) + 699 ((buffer[offset + 3] & 0xffL) << 32) + 700 ((buffer[offset + 4] & 0xffL) << 24) + 701 ((buffer[offset + 5] & 0xffL) << 16) + 702 ((buffer[offset + 6] & 0xffL) << 8) + 703 ((buffer[offset + 7] & 0xffL))); 704 } 705 706 709 public static void writeLong(byte []buffer, int offset, long v) 710 { 711 buffer[offset + 0] = (byte) (v >> 56); 712 buffer[offset + 1] = (byte) (v >> 48); 713 buffer[offset + 2] = (byte) (v >> 40); 714 buffer[offset + 3] = (byte) (v >> 32); 715 716 buffer[offset + 4] = (byte) (v >> 24); 717 buffer[offset + 5] = (byte) (v >> 16); 718 buffer[offset + 6] = (byte) (v >> 8); 719 buffer[offset + 7] = (byte) (v); 720 } 721 722 725 private static int readShort(byte []buffer, int offset) 726 { 727 return (((buffer[offset + 0] & 0xff) << 8) + 728 ((buffer[offset + 1] & 0xff))); 729 } 730 731 734 private static void writeShort(byte []buffer, int offset, int v) 735 { 736 buffer[offset + 0] = (byte) (v >> 8); 737 buffer[offset + 1] = (byte) v; 738 } 739 740 private static IllegalStateException stateError(String msg) 741 { 742 IllegalStateException e = new IllegalStateException (msg); 743 e.fillInStackTrace(); 744 log.log(Level.WARNING, e.toString(), e); 745 return e; 746 } 747 } 748 | Popular Tags |