1 8 package com.jofti.btree; 9 10 import java.lang.reflect.Array ; 11 import java.util.ArrayList ; 12 import java.util.Collection ; 13 import java.util.Iterator ; 14 import java.util.Map ; 15 import java.util.Properties ; 16 import java.util.Set ; 17 import java.util.Stack ; 18 19 import org.apache.commons.logging.Log; 20 import org.apache.commons.logging.LogFactory; 21 22 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicLong; 23 24 25 import com.jofti.core.IStoreManager; 26 import com.jofti.exception.JoftiException; 27 import com.jofti.locking.LockManager; 28 import com.jofti.oswego.concurrent.WriterPreferenceReadWriteLock; 29 import com.jofti.util.OpenHashMap; 30 31 32 41 public class BTree { 42 43 private static Log log = LogFactory.getLog(BTree.class); 44 45 private static int MAX_NODE_SIZE = 64; 47 48 private Node rootNode = null; 49 50 private NodeFactory factory=null; 51 52 public static LeafNodeEntry MAX_LEAF_ENTRY ; 53 54 55 public static final ValueObject MIN_RIGHT_VALUE = new ValueObject(Integer.MIN_VALUE,ValueObject.MIN_COMAPARBLE_VALUE); 56 57 private final WriterPreferenceReadWriteLock treeEntryLock = new WriterPreferenceReadWriteLock(); 59 60 61 private long nodes =0; 62 63 private AtomicLong entries =new AtomicLong(0); 65 66 IStoreManager overflowManager =null; 68 69 72 public BTree() 73 { 74 } 75 76 80 public BTree(int maxNodeSize) 81 { 82 MAX_NODE_SIZE = maxNodeSize; 83 } 84 85 88 public static int getMaxNodeSize(){ 89 return MAX_NODE_SIZE; 90 } 91 92 protected Node getRootNode() 93 { 94 return rootNode; 95 } 96 97 98 104 public void init(Properties props) throws JoftiException 105 { 106 107 factory = NodeFactory.getInstance(overflowManager); 109 110 MAX_LEAF_ENTRY = factory.createMaxLeafNodeEntry(); 111 112 LockManager.acquireRWLock(treeEntryLock, LockManager.WRITE_LOCK); 114 rootNode = factory.createLeafNode(); 115 rootNode.setEntries(new Object [BTree.getMaxNodeSize()]); 116 117 rootNode.setRightValue(MAX_LEAF_ENTRY.getValue()); 119 120 rootNode.insertEntry(MAX_LEAF_ENTRY); 122 nodes++; 123 LockManager.releaseRWLock(treeEntryLock, LockManager.WRITE_LOCK); 124 125 } 126 127 128 129 147 public void insert(NodeEntry entry) throws JoftiException 148 { 149 Stack nodeStack = new Stack (); 150 151 LockManager.acquireRWLock(treeEntryLock, LockManager.READ_LOCK); 153 try { 154 nodeStack.push(rootNode); 155 insert(entry, nodeStack); 156 entries.incrementAndGet(); 157 } finally{ 158 LockManager.releaseRWLock(treeEntryLock, LockManager.READ_LOCK); 159 } 160 } 161 162 173 public void removeAll(){ 174 175 try { 176 LockManager.acquireRWLock(treeEntryLock, LockManager.WRITE_LOCK); 177 178 if (overflowManager != null){ 180 overflowManager.removeAll(); 181 } 182 183 rootNode = factory.createLeafNode(); 184 rootNode.setEntries(new Object [BTree.getMaxNodeSize()]); 185 rootNode.setRightValue(MAX_LEAF_ENTRY.getValue()); 186 rootNode.insertEntry(MAX_LEAF_ENTRY); 187 nodes=1; 188 entries =new AtomicLong(0); 189 LockManager.releaseRWLock(treeEntryLock, LockManager.WRITE_LOCK); 190 } catch (JoftiException e){ 191 log.fatal("Error removing all entries ",e); 192 193 } 194 195 } 196 197 protected Node findNode(NodeEntry entry, Stack nodeStack) throws JoftiException 198 { 199 Node currentNode = (Node) nodeStack.pop(); 201 202 LockManager.acquireLock(currentNode, LockManager.READ_LOCK); 204 205 while (!currentNode.isLeaf()) 207 { 208 209 Object returnNode = scanNode(entry.getValue(), currentNode); 210 212 if (!(returnNode instanceof NodeLink)) 213 { 214 nodeStack.push(currentNode); 217 currentNode = (Node)returnNode; 218 } else 219 { 220 currentNode = (Node)((NodeLink) returnNode).getNode(); 221 } 222 } 224 225 LockManager.releaseLock(currentNode, LockManager.READ_LOCK); 227 228 232 LockManager.acquireLock(currentNode, LockManager.WRITE_LOCK); 233 234 237 currentNode = (Node)moveRight(currentNode, entry); 239 240 return currentNode; 241 } 242 243 244 protected void insert(NodeEntry entry, Stack nodeStack) throws JoftiException 245 { 246 247 Node currentNode = (Node)findNode(entry, nodeStack); 248 251 doInsert(currentNode, entry, nodeStack); 252 253 } 254 255 256 private void doInsert(Node currentNode, NodeEntry entry, Stack nodeStack) 257 throws JoftiException 258 { 259 260 Object [] temp = currentNode.insertEntry(entry); 262 263 if (currentNode.isUnderFull()) 265 { 266 LockManager.releaseLock(currentNode, LockManager.WRITE_LOCK); 268 } else 269 { 270 Node newNode = currentNode.splitNode(temp); 272 273 newNode.setLinkNode(currentNode.getLinkNode()); 276 277 IndexNodeEntry newEntry = constructKey(newNode); 279 newEntry.setValue(newNode.getRightValue()); 280 281 NodeLink newLink = new NodeLink(); 283 newLink.setNode(newNode); 284 currentNode.setLinkNode(newLink); 287 288 Node oldNode = currentNode; 294 nodes++; 295 if (nodeStack.isEmpty()) 297 { 298 299 IndexNode newRoot = factory.createIndexNode(); 300 301 newRoot.insertEntry(newEntry); 303 304 IndexNodeEntry originalEntry = constructKey(oldNode); 306 originalEntry.setValue(oldNode.getRightValue()); 307 308 newRoot.insertEntry(originalEntry); 309 310 newRoot.setRightValue(newEntry.getValue()); 312 313 rootNode = newRoot; 314 LockManager.releaseLock(oldNode, LockManager.WRITE_LOCK); 315 } else 316 { 317 currentNode = (Node) nodeStack.pop(); 318 LockManager.acquireLock(currentNode, LockManager.WRITE_LOCK); 320 currentNode = (Node)moveRight(currentNode, newEntry); 323 324 LockManager.releaseLock(oldNode, LockManager.WRITE_LOCK); 325 326 doInsert(currentNode, newEntry, nodeStack); 328 329 } 330 331 } 332 } 333 334 335 private Node moveRight(Node currentNode, NodeEntry value) 336 throws JoftiException 337 { 338 boolean rightnode = false; 339 while (!rightnode) 344 { 345 if (currentNode.getRightValue().compareTo(value.getValue()) >= 0) 347 { 348 rightnode = true; 349 350 } else 351 { 352 Node nextNode = (Node)currentNode.getLinkNode().getNode(); 356 357 LockManager.acquireLock(nextNode, LockManager.WRITE_LOCK); 358 while (nextNode.isDeleted()) 363 { 364 currentNode.setLinkNode(nextNode.getLinkNode()); 368 LockManager.releaseLock(nextNode, LockManager.WRITE_LOCK); 369 nextNode = (Node)currentNode.getLinkNode().getNode(); 370 LockManager.acquireLock(nextNode, LockManager.WRITE_LOCK); 371 } 372 LockManager.releaseLock(currentNode, LockManager.WRITE_LOCK); 374 currentNode = nextNode; 377 } 378 } 379 return currentNode; 382 } 383 384 385 private Object scanNode(Comparable value, Node startNode) 386 throws JoftiException 387 { 388 Node currentNode = startNode; 389 390 if (currentNode.getRightValue().compareTo(value) < 0) 394 { 395 396 NodeLink nodeLink = currentNode.getLinkNode(); 399 400 LockManager.releaseLock(currentNode, LockManager.READ_LOCK); 401 402 LockManager.acquireLock((Node)nodeLink.getNode(), LockManager.READ_LOCK); 403 404 return nodeLink; 405 } else 406 { 407 Node nextNode = ((IndexNode) currentNode).getContainingNode(value); 409 410 LockManager.releaseLock(currentNode, LockManager.READ_LOCK); 411 412 LockManager.acquireLock(nextNode, LockManager.READ_LOCK); 413 414 return nextNode; 415 416 } 417 } 418 419 420 431 public INode search(Comparable value) throws JoftiException 432 { 433 LockManager.acquireRWLock(treeEntryLock, LockManager.READ_LOCK); 434 try { 435 return realSearch(value, rootNode); 436 }finally{ 437 LockManager.releaseRWLock(treeEntryLock, LockManager.READ_LOCK); 438 } 439 } 440 441 442 443 454 455 456 public boolean containsDirect(Comparable value) throws JoftiException{ 457 458 LockManager.acquireRWLock(treeEntryLock, LockManager.READ_LOCK); 459 460 try{ 461 Node currentNode = rootNode; 462 LockManager.acquireLock(currentNode, LockManager.READ_LOCK); 463 464 while (!(currentNode.isLeaf())) 466 { 467 469 Object returnNode = scanNode(value, currentNode); 470 471 if (returnNode instanceof NodeLink) 474 { 475 currentNode = (Node)((NodeLink) returnNode).getNode(); 476 } else 477 { 478 currentNode = (Node) returnNode; 479 } 480 481 } 482 Node tempNode = scanLeafNode(currentNode, value); 484 boolean contains =false; 485 486 if (tempNode != null && (((Leaf)tempNode).getEntry(value) != null)){ 488 contains =true;; 489 } 490 491 492 493 LockManager.releaseLock(tempNode, LockManager.READ_LOCK); 495 496 return contains; 498 499 }finally{ 500 501 LockManager.releaseRWLock(treeEntryLock, LockManager.READ_LOCK); 502 503 } 504 505 } 506 507 508 509 protected Collection getAttributesDirect(Comparable value) 510 throws JoftiException { 511 Collection col = new ArrayList (); 512 513 LockManager.acquireRWLock(treeEntryLock, LockManager.READ_LOCK); 514 515 try { 516 Node currentNode = rootNode; 517 LockManager.acquireLock(currentNode, LockManager.READ_LOCK); 518 519 while (!(currentNode.isLeaf())) { 521 523 Object returnNode = scanNode(value, currentNode); 524 525 if (returnNode instanceof NodeLink) { 529 currentNode = (Node) ((NodeLink) returnNode).getNode(); 530 } else { 531 currentNode = (Node) returnNode; 532 } 533 534 } 535 Node tempNode = scanLeafNode(currentNode, value); 537 538 if (tempNode == null) { 539 return col; 540 } else { 541 try { 542 LeafNodeEntry val = ((Leaf) tempNode).getEntry(value); 546 547 if (val == null || val.getUniqueIdSet() == null 548 || val.getUniqueIdSet().isEmpty()) { 549 550 return col; 551 } else { 552 KeyValueObject attribWrapper = null; 555 try { 556 attribWrapper = (KeyValueObject) val.getValue(); 557 } catch (ClassCastException t) { 558 throw new JoftiException( 559 "key dimension must only contain KeyValueObjects"); 560 } 561 562 Set tempSet = attribWrapper.getAttributes().entrySet(); 563 Iterator other = tempSet.iterator(); 564 565 for (int j = tempSet.size(); j > 0; j--) { 566 Map.Entry entry = (Map.Entry ) other.next(); 567 Object tempVal = entry.getValue(); 568 if (tempVal.getClass().isArray()) { 569 int size = Array.getLength(tempVal); 570 for (int i = 0; i < size; i++) { 571 Object inner = Array.get(tempVal, i); 572 col.add(new ValueObject(((Integer ) entry 573 .getKey()).intValue(), 574 (Comparable ) inner)); 575 } 576 } else { 577 col.add(new ValueObject(((Integer ) entry 578 .getKey()).intValue(), 579 (Comparable ) entry.getValue())); 580 } 581 } 582 583 } 584 } finally { 585 LockManager.releaseLock(tempNode, LockManager.READ_LOCK); 587 } 588 } 589 590 } finally { 591 592 LockManager.releaseRWLock(treeEntryLock, LockManager.READ_LOCK); 593 594 } 595 return col; 596 597 } 598 599 600 609 protected OpenHashMap matchDirect(Comparable value, OpenHashMap map, final Object valueReturn) throws JoftiException{ 610 611 LockManager.acquireRWLock(treeEntryLock, LockManager.READ_LOCK); 612 613 try{ 614 Node currentNode = rootNode; 615 LockManager.acquireLock(currentNode, LockManager.READ_LOCK); 616 617 while (!(currentNode instanceof Leaf)) 619 { 620 622 Object returnNode = scanNode(value, currentNode); 623 624 if (returnNode instanceof NodeLink) 627 { 628 currentNode = (Node)((NodeLink) returnNode).getNode(); 629 } else 630 { 631 currentNode = (Node) returnNode; 632 } 633 634 } 635 Node tempNode = scanLeafNode(currentNode, value); 637 638 if (tempNode == null) { 640 if (map == null){ 641 return new OpenHashMap(1); 642 }else{ 643 return map; 644 } 645 } 646 648 try { 649 LeafNodeEntry val = ((Leaf)tempNode).getEntry(value); 650 651 652 if (val !=null){ 653 654 Object [] tempSet = val.uniqueIdSet.toArray(); 656 657 int setLength = tempSet.length; 658 if (map == null){ 661 map = new OpenHashMap(setLength*2,0.00f,0.5f); 662 664 for (int i=setLength-1;i>=0;i--) { 665 666 map.put(tempSet[i],valueReturn); 667 } 668 } else{ 669 map.ensureCapacity(map.size() + setLength); 671 672 for (int i=setLength-1;i>=0;i--) { 674 Object temp = tempSet[i]; 675 if (! map.containsKey(temp)){ 676 map.put(temp,valueReturn); 677 } 678 } 679 } 680 681 }else{ 682 if (map == null){ 684 map = new OpenHashMap(1); 685 } 686 } 687 688 } finally { 690 LockManager.releaseLock(tempNode, LockManager.READ_LOCK); 691 } 692 return map; 693 694 695 696 }finally{ 697 698 LockManager.releaseRWLock(treeEntryLock, LockManager.READ_LOCK); 699 700 } 701 702 } 703 704 705 private INode realSearch(Comparable value, Node currentNode) throws JoftiException 706 { 707 LockManager.acquireLock(currentNode, LockManager.READ_LOCK); 709 710 while (!(currentNode instanceof Leaf)) 712 { 713 715 Object returnNode = scanNode(value, currentNode); 716 717 if (returnNode instanceof NodeLink) 720 { 721 currentNode = (Node)((NodeLink) returnNode).getNode(); 722 } else 723 { 724 currentNode = (Node) returnNode; 725 } 726 727 } 728 Node tempNode = scanLeafNode(currentNode, value); 730 INode resultNode = new ResultNode(tempNode); 731 732 LockManager.releaseLock(tempNode, LockManager.READ_LOCK); 735 return resultNode; 736 } 737 738 739 private Node scanLeafNode(Node currentNode, Comparable value) 740 throws JoftiException 741 { 742 boolean rightnode = false; 743 while (!rightnode) 744 { 745 if (currentNode.contains(value)) 748 { 749 rightnode = true; 750 751 } else 752 { 753 Node nextNode = (Node)currentNode.getLinkNode().getNode(); 756 757 LockManager.releaseLock((Node)currentNode, LockManager.READ_LOCK); 758 759 LockManager.acquireLock((Node)nextNode, LockManager.READ_LOCK); 760 761 currentNode = nextNode; 762 } 763 } 764 return currentNode; 766 } 767 768 769 private IndexNodeEntry constructKey(Node childNode) 770 { 771 IndexNodeEntry nodeKey = factory 772 .createIndexNodeEntry(); 773 nodeKey.setValue(childNode.getRightValue()); 774 nodeKey.setChildNode(childNode); 775 return nodeKey; 776 } 777 778 779 789 public void removeEntry(NodeEntry entry) throws JoftiException 790 { 791 Stack nodeStack = new Stack (); 792 793 LockManager.acquireRWLock(treeEntryLock, LockManager.READ_LOCK); 794 try { 795 nodeStack.push(rootNode); 796 removeEntry(entry, nodeStack); 797 entries.decrementAndGet(); 798 }finally{ 799 800 LockManager.releaseRWLock(treeEntryLock, LockManager.READ_LOCK); 801 802 } 803 if (rootNode.getEntryNumber() == 1){ 804 collapseRoot(); 805 } 806 } 807 808 809 private void collapseRoot() throws JoftiException{ 810 LockManager.acquireRWLock(treeEntryLock, LockManager.WRITE_LOCK); 811 812 try { 815 816 while (rootNode instanceof IndexNode && rootNode.getEntryNumber() ==1){ 817 rootNode = ((IndexNodeEntry)rootNode.getEntries()[0]).getChildNode(); 818 } 819 }finally{ 820 821 LockManager.releaseRWLock(treeEntryLock, LockManager.WRITE_LOCK); 822 823 } 824 } 825 private void removeEntry(NodeEntry entry, Stack nodeStack) 826 throws JoftiException 827 { 828 Node currentNode = findNode(entry, nodeStack); 829 832 doRemove(currentNode, entry, nodeStack); 833 } 834 835 836 private void doRemove(Node currentNode, NodeEntry entry, Stack nodeStack) 837 throws JoftiException 838 { 839 840 843 Comparable oldRightValue = currentNode.getRightValue(); 844 boolean deleted = currentNode.deleteEntry(entry); 845 846 if (nodeStack.isEmpty() || !deleted 850 || (currentNode.getRightValue().compareTo(oldRightValue) == 0)) 851 { 852 853 LockManager.releaseLock((Node)currentNode, LockManager.WRITE_LOCK); 854 855 } else 856 { 857 IndexNodeEntry tempEntry = null; 860 861 if (entry instanceof IndexNodeEntry){ 862 tempEntry = (IndexNodeEntry)entry; 863 }else{ 864 tempEntry = factory 865 .createIndexNodeEntry(); 866 tempEntry.setValue(oldRightValue); 867 } 868 869 if (currentNode.isEmpty()) 871 { 872 873 currentNode.setRightValue(MIN_RIGHT_VALUE); 875 nodes --; 876 currentNode.setDeleted(true); 878 885 currentNode = obtainParentNode(currentNode, nodeStack, 886 tempEntry); 887 888 doRemove(currentNode, tempEntry, nodeStack); 890 } else 891 { 892 897 currentNode = obtainParentNode(currentNode, nodeStack, 899 tempEntry); 900 doUpdateIndexValue(currentNode, tempEntry, nodeStack); 902 903 } 904 } 905 906 } 907 908 909 910 private Node obtainParentNode(Node currentNode, Stack nodeStack, 911 IndexNodeEntry tempEntry) throws JoftiException 912 { 913 Node childNode = (Node)currentNode; 914 915 currentNode = (Node) nodeStack.pop(); 917 918 LockManager.acquireLock(currentNode, LockManager.WRITE_LOCK); 920 923 currentNode = (Node)moveRight(currentNode, tempEntry); 924 925 LockManager.releaseLock((Node)childNode, LockManager.WRITE_LOCK); 927 return currentNode; 928 } 929 930 931 private void doUpdateIndexValue(Node currentNode, NodeEntry entry, 932 Stack nodeStack) throws JoftiException 933 { 934 935 Comparable oldRightValue = currentNode.getRightValue(); 936 937 boolean updated = ((IndexNode) currentNode).updateEntry(entry); 938 if (nodeStack.isEmpty() || !updated 939 || (currentNode.getRightValue().compareTo(oldRightValue) == 0)) 940 { 941 LockManager.releaseLock((Node)currentNode, LockManager.WRITE_LOCK); 943 944 } else 945 { 946 currentNode = obtainParentNode(currentNode, nodeStack, 947 (IndexNodeEntry) entry); 948 949 doUpdateIndexValue(currentNode, entry, nodeStack); 950 } 951 952 } 953 954 955 958 public String toString() 959 { 960 StringBuffer buf = new StringBuffer (); 961 buf.append("number of nodes " + nodes + " number of entries "+ entries); 962 return buf.toString(); 963 } 964 965 969 public String treeToString() 970 { 971 StringBuffer buf = new StringBuffer (); 972 buf.append(rootNode); 973 return buf.toString(); 974 } 975 976 979 public long getEntries(){ 980 return entries.get(); 981 } 982 983 987 public IStoreManager getOverflowManager() { 988 return overflowManager; 989 } 990 991 995 public void setOverflowManager(IStoreManager overflowManager) { 996 this.overflowManager = overflowManager; 997 } 998 999 } | Popular Tags |