1 19 package org.netbeans.mdr.persistence.btreeimpl.btreeindex; 20 21 import org.netbeans.mdr.persistence.*; 22 import java.io.*; 23 import java.util.Arrays ; 24 25 30 public class ShrinkablePage extends BtreePage { 31 32 private static boolean debug = false; 33 34 private static final byte KEYS_SHRINKED_MASK = 1; 35 private static final byte DATA_SHRINKED_MASK = 2; 36 37 static final int KEY_ZERO_PREFIX_LENGTH = MOFID.LENGTH / 2; 39 static final int DATA_ZERO_PREFIX_LENGTH = MOFID.LENGTH / 2; 41 42 int keyLengthX; 44 int dataLengthX; 46 47 boolean keysShrinked; 49 boolean dataShrinked; 51 boolean keysShrinkable; 53 boolean dataShrinkable; 55 56 int currentKeyLength; 58 int currentDataLength; 60 61 67 68 boolean expandKeys; 70 boolean expandData; 72 73 83 public void init(Btree btree, byte[] pageId, byte[] pageBuffer, 84 boolean isNew) throws StorageException { 85 86 if (initialized) { 87 88 return; 89 } 90 91 super.init(btree, pageId, pageBuffer, isNew); 92 93 headerLength++; 94 95 keyLengthX = btree.keyInfo.getLength(); 96 dataLengthX = btree.dataInfo.getLength(); 97 98 keysShrinkable = btree.keyInfo instanceof MOFIDInfo; 99 dataShrinkable = btree.dataInfo instanceof MOFIDInfo; 100 101 if (isNew) { 102 keysShrinked = keysShrinkable; 103 dataShrinked = dataShrinkable; 104 freeStart++; 105 } else { 106 keysShrinked = (pageBuffer [headerLength - 1] & KEYS_SHRINKED_MASK) > 0; 107 dataShrinked = (pageBuffer [headerLength - 1] & DATA_SHRINKED_MASK) > 0; 108 } 109 110 currentKeyLength = keysShrinked ? MOFID.LENGTH / 2 : keyLengthX; 111 currentDataLength = dataShrinked ? MOFID.LENGTH / 2 : dataLengthX; 112 113 117 } 118 119 124 int numEntries() { 125 return (freeStart - headerLength)/(currentKeyLength + currentDataLength); 126 } 127 128 135 int keyOffset(int entryNum) { 136 return headerLength + (entryNum * (currentKeyLength + currentDataLength)); 137 } 138 139 146 int keyLength(int entryNum) { 147 return keyLengthX; 148 } 149 150 157 byte[] getData(int entryNum) { 158 byte[] data = new byte[dataLengthX]; 159 if (dataShrinked) { 160 System.arraycopy(pageBuffer, keyOffset(entryNum) + currentKeyLength, 161 data, DATA_ZERO_PREFIX_LENGTH, currentDataLength); 162 } else { 163 System.arraycopy(pageBuffer, keyOffset(entryNum) + currentKeyLength, 164 data, 0, currentDataLength); 165 } 166 167 if (debug) { 168 System.out.println("getData called: " + entryNum); 169 } 170 171 return data; 172 } 173 174 181 byte[] getKey(int entryNum) { 182 byte[] key = new byte[keyLengthX]; 183 if (keysShrinked) { 184 System.arraycopy(pageBuffer, keyOffset(entryNum), key, 185 KEY_ZERO_PREFIX_LENGTH, currentKeyLength); 186 } else { 187 System.arraycopy(pageBuffer, keyOffset(entryNum), key, 0, currentKeyLength); 188 } 189 190 if (debug) { 191 System.out.print("getKey: "); 192 for (int x = 0; x < key.length; x++) 193 System.out.print(key[x] + ":"); 194 System.out.println(""); 195 } 196 return key; 197 } 198 199 protected byte compare(byte[] key, int entryNum) { 200 201 if (!isLeaf() && (entryNum == 0) 202 && pageSource.isNoPage(previousPage)) { 203 return EntryTypeInfo.GREATER; 204 } 205 206 int index = 0; 207 byte k,p; 208 if (keysShrinkable && keysShrinked) { 209 for (; index < KEY_ZERO_PREFIX_LENGTH; index++) { 210 k = key[index]; 211 if (k < 0) { 212 return EntryTypeInfo.LESS; 213 } else if (k > 0) { 214 return EntryTypeInfo.GREATER; 215 } 216 } } int offset = keyOffset (entryNum); 219 for (; index < key.length; index++, offset++) { 220 k = key[index]; 221 p = pageBuffer[offset]; 222 if (k < p) { 223 return EntryTypeInfo.LESS; 224 } else if (k > p) { 225 return EntryTypeInfo.GREATER; 226 } 227 } 228 return EntryTypeInfo.EQUAL; 229 } 230 231 protected byte compareData(byte[] data, int entryNum) { 232 233 int index = 0; 234 byte d,p; 235 if (dataShrinkable && dataShrinked) { 236 for (; index < DATA_ZERO_PREFIX_LENGTH; index++) { 237 d = data[index]; 238 if (d < 0) { 239 return EntryTypeInfo.LESS; 240 } else if (d > 0) { 241 return EntryTypeInfo.GREATER; 242 } 243 } } int offset = keyOffset (entryNum) + currentKeyLength; 246 for (; index < data.length; index++, offset++) { 247 d = data[index]; 248 p = pageBuffer[offset]; 249 if (d < p) { 250 return EntryTypeInfo.LESS; 251 } else if (d > p) { 252 return EntryTypeInfo.GREATER; 253 } 254 } 255 return EntryTypeInfo.EQUAL; 256 } 257 258 267 BtreeEntry insert(BtreeEntry entry, int entryNum, SearchResult resultPosition) 268 throws StorageException { 269 270 if (debug) { 271 System.out.print("insert called: "); 272 for (int x = 0; x < entry.key.length; x++) { 273 System.out.print(entry.key [x]); 274 } 275 System.out.println(""); 276 } 277 278 if (debug) { 279 for (int x = 0; x < entry.key.length; x++) 280 System.out.print(entry.key[x] + ":"); 281 System.out.print(" "); 282 for (int x = 0; x < entry.data.length; x++) 283 System.out.print(entry.data[x] + ":"); 284 System.out.println(); 285 } 286 287 int space = 0; 288 289 expandKeys = false; 290 expandData = false; 291 292 pageSource.dirtyPage(this); 293 294 if (keysShrinked && hasLongKey (entry)) { 295 expandKeys = true; 296 space += numEntries () * KEY_ZERO_PREFIX_LENGTH + entry.key.length; 297 } 298 if (dataShrinked && hasLongData (entry)) { 299 expandData = true; 300 space += numEntries () * DATA_ZERO_PREFIX_LENGTH + entry.data.length; 301 } 302 if (!expandKeys) 303 space += currentKeyLength; 304 if (!expandData) 305 space += currentDataLength; 306 307 if (btree.pageSize - freeStart - keyLengthX - dataLengthX >= space) { 308 insertHere(entry, entryNum, resultPosition); 309 return null; 310 } else { 311 BtreeEntry result = split(entry, entryNum, resultPosition); 312 return result; 313 } 314 } 315 316 324 BtreeEntry replace(BtreeEntry entry, int entryNum, SearchResult position) throws StorageException { 325 326 if (debug) { 327 System.out.println("replace called"); 328 } 329 330 pageSource.dirtyPage(this); 331 332 if (dataShrinked && hasLongData (entry)) { 333 int space = numEntries () * (currentKeyLength + dataLengthX); 334 if (btree.pageSize - freeStart - keyLengthX - dataLengthX < space) { 335 delete (entryNum, entryNum); 336 return insert (entry, entryNum, position); 337 } else { 338 expandData (); 339 } 340 } 341 342 int offset = keyOffset(entryNum) + currentKeyLength; 343 int dataStart = dataShrinked ? DATA_ZERO_PREFIX_LENGTH : 0; 344 System.arraycopy(entry.data, dataStart, pageBuffer, offset, currentDataLength); 345 346 return null; 347 } 348 349 private void insertHere(BtreeEntry entry, int entryNum, SearchResult resultPosition) { 350 351 if (debug) { 352 dump (); 354 dumpBuffer (); 355 } 357 358 int offset; 359 if (expandKeys) 360 expandKeys (); 361 if (expandData) 362 expandData (); 363 364 offset = keyOffset(entryNum); 365 if (offset != freeStart) { 366 367 System.arraycopy(pageBuffer, offset, 368 pageBuffer, offset + (currentKeyLength + currentDataLength), 369 freeStart - offset); 370 } 371 copyEntry (offset, entry); 372 freeStart += currentKeyLength + currentDataLength; 373 374 if (resultPosition != null) { 375 resultPosition.entryNum = entryNum; 376 resultPosition.matched = true; 377 resultPosition.page = this; 378 resultPosition.skipCount = 0; 379 } 380 381 if (debug) { 382 for (int x = 0; x < entry.key.length; x++) { 385 System.out.print(entry.key [x]); 386 } 387 System.out.println(""); 388 dump (); 389 dumpBuffer (); 390 } 392 393 } 394 395 401 void delete(int firstEntry, int lastEntry) throws StorageException { 402 int startOffset, endOffset; 403 404 if (debug) { 405 System.out.println("delete called: " + firstEntry + " " + lastEntry); 406 } 407 408 pageSource.dirtyPage(this); 409 410 startOffset = keyOffset(firstEntry); 411 endOffset = keyOffset(lastEntry+1); 412 if (freeStart != endOffset) { 413 System.arraycopy(pageBuffer, endOffset, pageBuffer, startOffset, 414 freeStart - endOffset); 415 } 416 freeStart -= endOffset - startOffset; 417 } 418 419 432 byte[] splitEntries(BtreePage leftPage, BtreePage rightPage, BtreeEntry entry, 433 int entryNum, SearchResult resultPosition) { 434 435 int entryLength; 436 int offset; 437 int midpoint; 438 int half; 439 int copyLength; 440 boolean insertLeft; 441 442 if (debug) { 443 System.out.println("Split entries called."); 444 } 445 446 ShrinkablePage left = (ShrinkablePage) leftPage; 447 ShrinkablePage right = (ShrinkablePage) rightPage; 448 449 copyState (right); 450 if (left != this) 451 copyState (left); 452 453 offset = keyOffset(entryNum); 454 entryLength = currentKeyLength + currentDataLength; 455 half = numEntries()/2; 456 midpoint = headerLength + half*entryLength; 457 insertLeft = offset < midpoint; 458 459 if (insertLeft) { 461 copyLength = this.freeStart - midpoint; 462 } else { 463 copyLength = offset - midpoint; 465 } 466 467 if (resultPosition != null) { 469 resultPosition.matched = true; 470 resultPosition.skipCount = 0; 471 if (insertLeft) { 472 resultPosition.page = left; 473 resultPosition.entryNum = entryNum; 474 } else { 475 resultPosition.page = right; 476 resultPosition.entryNum = entryNum - half; 477 } 478 } 479 480 if (copyLength > 0) { 481 System.arraycopy(this.pageBuffer, midpoint, right.pageBuffer, 482 right.freeStart, copyLength); 483 right.freeStart += copyLength; 484 } 485 if (!insertLeft) { 486 right.freeStart += currentKeyLength; 488 right.freeStart += currentDataLength; 490 if (this.freeStart != offset) { 491 System.arraycopy(this.pageBuffer, offset, right.pageBuffer, 492 right.freeStart, this.freeStart - offset); 493 right.freeStart += this.freeStart - offset; 494 } 495 if (expandKeys) 496 right.expandKeys (); 497 if (expandData) 498 right.expandData (); 499 right.copyEntry (right.keyOffset (entryNum - half), entry); 500 } 501 502 if (left != this) { 505 if (insertLeft) { 506 copyLength = offset - headerLength; 507 } else { 508 copyLength = midpoint - headerLength; 509 } 510 if (copyLength > 0) { 511 System.arraycopy(this.pageBuffer, headerLength, 512 left.pageBuffer, left.freeStart, copyLength); 513 } 514 } 515 516 if (insertLeft) { 517 if (midpoint != offset) { 518 System.arraycopy(this.pageBuffer, offset, left.pageBuffer, 519 offset+entryLength, midpoint - offset); 520 } 521 left.freeStart = midpoint + entryLength; 522 if (expandKeys) 523 left.expandKeys (); 524 if (expandData) 525 left.expandData (); 526 left.copyEntry (keyOffset (entryNum), entry); 527 } else { 530 left.freeStart = midpoint; 531 } 532 if (left != this) { 533 this.freeStart = headerLength; 535 } 536 541 542 558 559 561 return right.getKey (0); 562 } 563 564 public void store() { 565 566 super.store(); 567 568 byte val = 0; 569 if (keysShrinked) { 570 val += KEYS_SHRINKED_MASK; 571 } 572 if (dataShrinked) { 573 val += DATA_SHRINKED_MASK; 574 } 575 pageBuffer [headerLength - 1] = val; 576 } 577 578 580 583 private boolean hasLongKey (BtreeEntry entry) { 584 for (int x = 0; x < KEY_ZERO_PREFIX_LENGTH; x++) { 585 if (entry.key [x] != 0) 586 return true; 587 } return false; 589 } 590 591 594 private boolean hasLongData (BtreeEntry entry) { 595 for (int x = 0; x < KEY_ZERO_PREFIX_LENGTH; x++) { 596 if (entry.data [x] != 0) 597 return true; 598 } return false; 600 } 601 602 void expandKeys () { 603 if (debug) { 604 System.out.println("expand keys called"); 605 dump (); 606 } 607 608 int numEntries = numEntries (); 609 int length = numEntries * (currentKeyLength + currentDataLength); 610 byte [] tempBuffer = new byte [length]; 611 System.arraycopy (pageBuffer, headerLength, tempBuffer, 0, length); 612 for (int i = 0; i < numEntries; i++) { 613 int index = headerLength + i*(keyLengthX + currentDataLength); 614 Arrays.fill (pageBuffer, index, 615 index + KEY_ZERO_PREFIX_LENGTH, (byte) 0); 616 System.arraycopy (tempBuffer, i*(currentKeyLength + currentDataLength), pageBuffer, 617 KEY_ZERO_PREFIX_LENGTH + index, 618 currentKeyLength + currentDataLength); 619 } 620 freeStart += numEntries * KEY_ZERO_PREFIX_LENGTH; 621 currentKeyLength = keyLengthX; 622 keysShrinked = false; 623 624 if (debug) { 625 dump (); 626 } 627 } 628 629 void expandData () { 630 if (debug) { 631 System.out.println("expand data called"); 632 } 633 634 int numEntries = numEntries (); 635 int length = numEntries * (currentKeyLength + currentDataLength); 636 byte [] tempBuffer = new byte [length]; 637 System.arraycopy (pageBuffer, headerLength, tempBuffer, 0, length); 638 for (int i = 0; i < numEntries; i++) { 639 int index = headerLength + currentKeyLength + i*(currentKeyLength + dataLengthX); 640 System.arraycopy (tempBuffer, 641 i*(currentKeyLength + currentDataLength), 642 pageBuffer, 643 headerLength + i*(keyLengthX + currentDataLength), currentKeyLength); 644 Arrays.fill (pageBuffer, 645 index, 646 index + DATA_ZERO_PREFIX_LENGTH, (byte) 0); 647 System.arraycopy (tempBuffer, 648 currentKeyLength + i*(currentKeyLength + currentDataLength), 649 pageBuffer, 650 headerLength + currentKeyLength + DATA_ZERO_PREFIX_LENGTH + i*(keyLengthX + currentDataLength), 651 currentDataLength); 652 } 653 freeStart += numEntries * DATA_ZERO_PREFIX_LENGTH; 654 currentDataLength = dataLengthX; 655 dataShrinked = false; 656 } 657 658 void copyEntry (int offset, BtreeEntry entry) { 659 int keyStart = keysShrinked ? KEY_ZERO_PREFIX_LENGTH : 0; 660 int dataStart = dataShrinked ? DATA_ZERO_PREFIX_LENGTH : 0; 661 System.arraycopy(entry.key, keyStart, pageBuffer, offset, currentKeyLength); 662 System.arraycopy(entry.data, dataStart, pageBuffer, 663 offset + currentKeyLength, currentDataLength); 664 } 665 666 private void copyState (ShrinkablePage page) { 667 page.keysShrinked = keysShrinked; 668 page.dataShrinked = dataShrinked; 669 page.currentKeyLength = currentKeyLength; 670 page.currentDataLength = currentDataLength; 671 } 672 673 public void dump () { 674 System.out.println("# entries: " + numEntries () + " ------------------"); 675 for (int i = 0; i < numEntries (); i++) { 676 boolean temp = debug; 677 debug = true; 678 getKey (i); 679 System.out.print(" "); 680 getData (i); 681 debug = temp; 682 } 683 System.out.println("----------------------------------"); 684 } 685 686 public void dumpBuffer () { 687 System.out.print("buff: "); 688 for (int x = headerLength; x < freeStart; x++) { 689 System.out.print(pageBuffer[x] + "."); 690 } 691 System.out.println(""); 692 } 693 694 } 695 | Popular Tags |