1 21 22 package org.apache.derby.iapi.store.access; 23 24 import org.apache.derby.iapi.services.sanity.SanityManager; 25 26 import org.apache.derby.iapi.services.io.Storable; 27 28 import org.apache.derby.iapi.error.StandardException; 29 30 import org.apache.derby.iapi.types.CloneableObject; 31 import org.apache.derby.iapi.types.DataValueDescriptor; 32 33 import org.apache.derby.iapi.services.cache.ClassSize; 34 35 import java.util.Enumeration ; 36 import java.util.Hashtable ; 37 import java.util.Properties ; 38 import java.util.Vector ; 39 import java.util.NoSuchElementException ; 40 41 101 102 public class BackingStoreHashtable 103 { 104 105 109 private TransactionController tc; 110 private Hashtable hash_table; 111 private int[] key_column_numbers; 112 private boolean remove_duplicates; 113 private boolean skipNullKeyColumns; 114 private Properties auxillary_runtimestats; 115 private RowSource row_source; 116 120 private long max_inmemory_rowcnt; 121 private long inmemory_rowcnt; 122 private long max_inmemory_size; 123 private boolean keepAfterCommit; 124 125 128 private final static int vectorSize = ClassSize.estimateBaseFromCatalog(java.util.Vector .class); 129 130 private DiskHashtable diskHashtable; 131 132 136 private BackingStoreHashtable(){} 137 138 190 public BackingStoreHashtable( 191 TransactionController tc, 192 RowSource row_source, 193 int[] key_column_numbers, 194 boolean remove_duplicates, 195 long estimated_rowcnt, 196 long max_inmemory_rowcnt, 197 int initialCapacity, 198 float loadFactor, 199 boolean skipNullKeyColumns, 200 boolean keepAfterCommit) 201 throws StandardException 202 { 203 this.key_column_numbers = key_column_numbers; 204 this.remove_duplicates = remove_duplicates; 205 this.row_source = row_source; 206 this.skipNullKeyColumns = skipNullKeyColumns; 207 this.max_inmemory_rowcnt = max_inmemory_rowcnt; 208 if( max_inmemory_rowcnt > 0) 209 max_inmemory_size = Long.MAX_VALUE; 210 else 211 max_inmemory_size = Runtime.getRuntime().totalMemory()/100; 212 this.tc = tc; 213 this.keepAfterCommit = keepAfterCommit; 214 215 Object [] row; 216 217 if (initialCapacity != -1) 220 { 221 hash_table = 222 ((loadFactor == -1) ? 223 new Hashtable (initialCapacity) : 224 new Hashtable (initialCapacity, loadFactor)); 225 } 226 else 227 { 228 253 hash_table = 254 (((estimated_rowcnt <= 0) || (row_source == null)) ? 255 new Hashtable () : 256 (estimated_rowcnt < max_inmemory_size) ? 257 new Hashtable ((int) estimated_rowcnt) : 258 null); 259 } 260 261 if (row_source != null) 262 { 263 boolean needsToClone = row_source.needsToClone(); 264 265 while ((row = getNextRowFromRowSource()) != null) 266 { 267 if (hash_table == null) 276 { 277 double rowUsage = getEstimatedMemUsage(row); 281 hash_table = new Hashtable ((int)(max_inmemory_size / rowUsage)); 282 } 283 284 add_row_to_hash_table(hash_table, row, needsToClone); 285 } 286 } 287 288 if (hash_table == null) 296 hash_table = new Hashtable (); 297 } 298 299 303 304 311 private Object [] getNextRowFromRowSource() 312 throws StandardException 313 { 314 Object [] row = row_source.getNextRowFromRowSource(); 315 316 if (skipNullKeyColumns) 317 { 318 while (row != null) 319 { 320 int index = 0; 322 for ( ; index < key_column_numbers.length; index++) 323 { 324 if (SanityManager.DEBUG) 325 { 326 if (! (row[key_column_numbers[index]] instanceof Storable)) 327 { 328 SanityManager.THROWASSERT( 329 "row[key_column_numbers[index]] expected to be Storable, not " + 330 row[key_column_numbers[index]].getClass().getName()); 331 } 332 } 333 Storable storable = (Storable) row[key_column_numbers[index]]; 334 if (storable.isNull()) 335 { 336 break; 337 } 338 } 339 if (index == key_column_numbers.length) 341 { 342 return row; 343 } 344 row = row_source.getNextRowFromRowSource(); 346 } 347 } 348 return row; 349 } 350 351 358 static Object [] cloneRow(Object [] old_row) 359 throws StandardException 360 { 361 Object [] new_row = new DataValueDescriptor[old_row.length]; 362 363 for (int i = 0; i < old_row.length; i++) 366 { 367 if( old_row[i] != null) 368 new_row[i] = ((DataValueDescriptor) old_row[i]).getClone(); 369 } 370 371 return(new_row); 372 } 373 374 381 static DataValueDescriptor[] shallowCloneRow(DataValueDescriptor[] old_row) 382 throws StandardException 383 { 384 DataValueDescriptor[] new_row = new DataValueDescriptor[old_row.length]; 385 for (int i = 0; i < old_row.length; i++) 388 { 389 if( old_row[i] != null) 390 new_row[i] = (DataValueDescriptor) 391 ((CloneableObject) old_row[i]).cloneObject(); 392 } 393 394 return(new_row); 395 } 396 397 407 private void add_row_to_hash_table( 408 Hashtable hash_table, 409 Object [] row, 410 boolean needsToClone ) 411 throws StandardException 412 { 413 if( spillToDisk( hash_table, row)) 414 return; 415 416 if (needsToClone) 417 { 418 row = cloneRow(row); 419 } 420 Object key = KeyHasher.buildHashKey(row, key_column_numbers); 421 Object duplicate_value = null; 422 423 if ((duplicate_value = hash_table.put(key, row)) == null) 424 doSpaceAccounting( row, false); 425 else 426 { 427 if (!remove_duplicates) 428 { 429 Vector row_vec; 430 431 if ((duplicate_value instanceof Vector )) 433 { 434 doSpaceAccounting( row, false); 435 row_vec = (Vector ) duplicate_value; 436 } 437 else 438 { 439 row_vec = new Vector (2); 441 442 row_vec.addElement(duplicate_value); 444 doSpaceAccounting( row, true); 445 } 446 447 row_vec.addElement(row); 449 450 hash_table.put(key, row_vec); 454 } 455 } 456 457 row = null; 458 } 459 460 private void doSpaceAccounting( Object [] row, 461 boolean firstDuplicate) 462 { 463 inmemory_rowcnt++; 464 if( max_inmemory_rowcnt <= 0) 465 { 466 max_inmemory_size -= getEstimatedMemUsage(row); 467 if( firstDuplicate) 468 max_inmemory_size -= vectorSize; 469 } 470 } 472 482 private boolean spillToDisk( Hashtable hash_table, 483 Object [] row) 484 throws StandardException 485 { 486 if( diskHashtable == null) 489 { 490 if( max_inmemory_rowcnt > 0) 491 { 492 if( inmemory_rowcnt < max_inmemory_rowcnt) 493 return false; } 495 else if( max_inmemory_size > getEstimatedMemUsage(row)) 496 497 return false; 498 if( ! (row instanceof DataValueDescriptor[])) 500 { 501 if( SanityManager.DEBUG) 502 SanityManager.THROWASSERT( "BackingStoreHashtable row is not DataValueDescriptor[]"); 503 return false; 505 } 506 diskHashtable = new DiskHashtable( tc, 507 (DataValueDescriptor[]) row, 508 key_column_numbers, 509 remove_duplicates, 510 keepAfterCommit); 511 } 512 Object key = KeyHasher.buildHashKey(row, key_column_numbers); 513 Object duplicateValue = hash_table.get( key); 514 if( duplicateValue != null) 515 { 516 if( remove_duplicates) 517 return true; if( duplicateValue instanceof Vector ) 521 { 522 Vector duplicateVec = (Vector ) duplicateValue; 523 for( int i = duplicateVec.size() - 1; i >= 0; i--) 524 { 525 Object [] dupRow = (Object []) duplicateVec.elementAt(i); 526 diskHashtable.put( key, dupRow); 527 } 528 } 529 else 530 diskHashtable.put( key, (Object []) duplicateValue); 531 hash_table.remove( key); 532 } 533 diskHashtable.put( key, row); 534 return true; 535 } 537 545 private long getEstimatedMemUsage(Object [] row) 546 { 547 long rowMem = 0; 548 for( int i = 0; i < row.length; i++) 549 { 550 if (row[i] instanceof DataValueDescriptor) 551 rowMem += ((DataValueDescriptor) row[i]).estimateMemoryUsage(); 552 rowMem += ClassSize.refSize; 553 } 554 555 rowMem += ClassSize.refSize; 556 return rowMem; 557 } 558 559 563 564 574 public void close() 575 throws StandardException 576 { 577 hash_table = null; 578 if( diskHashtable != null) 579 { 580 diskHashtable.close(); 581 diskHashtable = null; 582 } 583 return; 584 } 585 586 596 public Enumeration elements() 597 throws StandardException 598 { 599 if( diskHashtable == null) 600 return(hash_table.elements()); 601 return new BackingStoreHashtableEnumeration(); 602 } 603 604 638 public Object get(Object key) 639 throws StandardException 640 { 641 Object obj = hash_table.get(key); 642 if( diskHashtable == null || obj != null) 643 return obj; 644 return diskHashtable.get( key); 645 } 646 647 655 public void getAllRuntimeStats(Properties prop) 656 throws StandardException 657 { 658 if (auxillary_runtimestats != null) 659 org.apache.derby.iapi.util.PropertyUtil.copyProperties(auxillary_runtimestats, prop); 660 } 661 662 671 public Object remove( 672 Object key) 673 throws StandardException 674 { 675 Object obj = hash_table.remove(key); 676 if( obj != null || diskHashtable == null) 677 return obj; 678 return diskHashtable.remove(key); 679 } 680 681 693 public void setAuxillaryRuntimeStats(Properties prop) 694 throws StandardException 695 { 696 auxillary_runtimestats = prop; 697 } 698 699 723 public boolean put( 724 boolean needsToClone, 725 Object [] row) 726 throws StandardException 727 { 728 if (skipNullKeyColumns) 730 { 731 int index = 0; 732 for ( ; index < key_column_numbers.length; index++) 733 { 734 if (SanityManager.DEBUG) 735 { 736 if (! (row[key_column_numbers[index]] instanceof Storable)) 737 { 738 SanityManager.THROWASSERT( 739 "row[key_column_numbers[index]] expected to be Storable, not " + 740 row[key_column_numbers[index]].getClass().getName()); 741 } 742 } 743 Storable storable = (Storable) row[key_column_numbers[index]]; 744 if (storable.isNull()) 745 { 746 return false; 747 } 748 } 749 } 750 751 Object key = KeyHasher.buildHashKey(row, key_column_numbers); 752 753 if ((remove_duplicates) && (get(key) != null)) 754 { 755 return(false); 756 } 757 else 758 { 759 add_row_to_hash_table(hash_table, row, needsToClone); 760 return(true); 761 } 762 } 763 764 772 public int size() 773 throws StandardException 774 { 775 if( diskHashtable == null) 776 return(hash_table.size()); 777 return hash_table.size() + diskHashtable.size(); 778 } 779 780 private class BackingStoreHashtableEnumeration implements Enumeration 781 { 782 private Enumeration memoryEnumeration; 783 private Enumeration diskEnumeration; 784 785 BackingStoreHashtableEnumeration() 786 { 787 memoryEnumeration = hash_table.elements(); 788 if( diskHashtable != null) 789 { 790 try 791 { 792 diskEnumeration = diskHashtable.elements(); 793 } 794 catch( StandardException se) 795 { 796 diskEnumeration = null; 797 } 798 } 799 } 800 801 public boolean hasMoreElements() 802 { 803 if( memoryEnumeration != null) 804 { 805 if( memoryEnumeration.hasMoreElements()) 806 return true; 807 memoryEnumeration = null; 808 } 809 if( diskEnumeration == null) 810 return false; 811 return diskEnumeration.hasMoreElements(); 812 } 813 814 public Object nextElement() throws NoSuchElementException 815 { 816 if( memoryEnumeration != null) 817 { 818 if( memoryEnumeration.hasMoreElements()) 819 return memoryEnumeration.nextElement(); 820 memoryEnumeration = null; 821 } 822 return diskEnumeration.nextElement(); 823 } 824 } } 826 | Popular Tags |