1 package org.ozoneDB.core; 9 10 import org.ozoneDB.DxLib.DxIterator; 11 import org.ozoneDB.*; 12 import org.ozoneDB.util.LogWriter; 13 import org.ozoneDB.data.SimpleArrayList; 14 import org.ozoneDB.io.stream.NullOutputStream; 15 16 import java.io.IOException ; 17 import java.io.ObjectOutputStream ; 18 import java.util.HashSet ; 19 import java.util.LinkedList ; 20 21 53 public class GarbageCollector extends ServerComponent implements Runnable { 54 55 58 60 63 protected Thread garbageCollectionThread; 64 65 70 protected HashSet transactionsRequiredToComplete; 71 72 82 protected int currentGarbageCollectionLevel; 83 84 88 protected int doneReachableGarbageCollectionLevel; 89 90 93 protected int phase = PHASE_IDLE; 94 95 96 protected final static int PHASE_IDLE = 0; 97 98 99 protected final static int PHASE_RUN_INITIATED = 1; 100 101 102 protected final static int PHASE_WAITING_FOR_OLD_TRANSACTIONS_TO_COMPLETE = 2; 103 104 105 protected final static int PHASE_READY_TO_START = 3; 106 107 108 protected final static int PHASE_MARKING = 4; 109 110 111 protected final static int PHASE_WAITING_FOR_NEW_TRANSACTIONS_TO_COMPLETE = 5; 112 113 114 protected final static int PHASE_MARKING2 = 6; 115 116 117 protected final static int PHASE_SWEEPING = 7; 118 119 120 122 125 protected Transaction transaction; 126 127 130 protected int actionsWithinTransactionCount = 0; 131 132 137 protected SimpleArrayList surelyReachableObjectsWhichHaveToBeMarkedAsSuch; 139 140 147 protected LinkedList surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented; 148 149 153 protected Object garbageCollectionLevelsLock = new Object (); 154 155 159 protected boolean kill = false; 160 161 164 protected GarbageCollector(Env env) { 165 super(env); 166 setCurrentGarbageCollectionLevel(env.getState().intProperty(env.getState().GARBAGE_COLLECTION_LEVEL,0)); 168 surelyReachableObjectsWhichHaveToBeMarkedAsSuch = new SimpleArrayList(10000); surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented = new LinkedList (); 171 transactionsRequiredToComplete = new HashSet (); 172 } 173 174 protected void setCurrentGarbageCollectionLevel(int to) { 175 synchronized (garbageCollectionLevelsLock) { 176 this.currentGarbageCollectionLevel = to; 177 this.doneReachableGarbageCollectionLevel = this.currentGarbageCollectionLevel+1; 178 } 179 } 180 181 public void startup() { 182 env.getLogWriter().newEntry( this, "startup...", LogWriter.INFO); 183 env.getLogWriter().newEntry( this, "garbageCollection level set to " + currentGarbageCollectionLevel, LogWriter.DEBUG); 184 } 185 186 187 public void shutdown() { 188 kill = true; 189 } 190 191 192 public void save() { 193 } 194 195 198 public void start() { 199 env.getLogWriter().newEntry(this,"start()", LogWriter.DEBUG1); 200 synchronized (this) { 201 if (phase==PHASE_IDLE) { 202 if (garbageCollectionThread==null) { 203 setPhase(PHASE_RUN_INITIATED); 204 garbageCollectionThread = env.getInvokeServer().newThread(this); 205 garbageCollectionThread.start(); 206 } else { 207 } 209 } else { 210 } 212 } 213 } 214 215 public void addTransactionRequiredToComplete(Object ta) { 216 transactionsRequiredToComplete.add(ta); 217 } 218 219 public void removeTransactionRequiredToComplete(Transaction ta) { 220 if (!transactionsRequiredToComplete.isEmpty()) { 221 transactionsRequiredToComplete.remove(ta); 222 checkForEndOfWaitForCurrentTransactionsToCompletePhase(); 223 } 224 } 225 226 protected void checkForEndOfWaitForCurrentTransactionsToCompletePhase() { 227 if (transactionsRequiredToComplete.isEmpty()) { 228 notifyEndOfWaitForCurrentTransactionsToCompletePhase(); 229 } 230 } 231 232 236 protected void notifyEndOfWaitForCurrentTransactionsToCompletePhase() { 237 synchronized (this) { 238 243 setPhase(phase+1); 244 notify(); 245 } 246 } 247 248 protected void incCurrentGarbageCollectorLevel() { 249 setCurrentGarbageCollectionLevel(currentGarbageCollectionLevel+4); 250 env.getState().setIntProperty(env.getState().GARBAGE_COLLECTION_LEVEL,currentGarbageCollectionLevel); 251 setChanged(); 252 } 253 254 257 public void run() { 258 env.getLogWriter().newEntry(this,"garbage collection running...",LogWriter.DEBUG); 259 try { 260 incCurrentGarbageCollectorLevel(); 261 262 setPhase(PHASE_WAITING_FOR_OLD_TRANSACTIONS_TO_COMPLETE); 263 264 env.getTransactionManager().startGarbageCollectionWaitForCurrentTransactionsToCompletePhase(this); 265 266 waitForPhase(PHASE_READY_TO_START); 267 268 renewTransactionIfRequired(); 269 270 addRootSetElementsToSurelyReachableSet(); 271 272 setPhase(PHASE_MARKING); 273 274 processSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(); 275 276 if (kill) { 277 return; 278 } 279 280 setPhase(PHASE_WAITING_FOR_NEW_TRANSACTIONS_TO_COMPLETE); 281 282 env.getTransactionManager().startGarbageCollectionWaitForCurrentTransactionsToCompletePhase(this); 283 284 waitForPhase(PHASE_MARKING2); 285 286 processSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(); 287 288 if (kill) { 289 return; 290 } 291 292 setPhase(PHASE_SWEEPING); 293 294 sweepUnreachableObjects(); 295 296 } catch (Throwable e) { 297 env.getLogWriter().newEntry(this,"GC caught: ",e,env.getLogWriter().ERROR); 298 } finally { 299 env.getLogWriter().newEntry(this,"garbage collection end...",LogWriter.DEBUG); 300 garbageCollectionThread = null; 301 setPhase(PHASE_IDLE); 302 try { 303 if (transaction!=null) { internalAbortTransaction(transaction); 305 env.getTransactionManager().deleteTransaction(); 307 transaction = null; 308 } 309 } catch (ClassNotFoundException e) { 310 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 311 } catch (IOException e) { 312 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 313 } 314 } 315 } 316 317 protected void notifyAboutTransactionActionAndRenewTransactionIfRequired() throws IOException ,ClassNotFoundException ,TransactionException { 318 renewTransactionIfRequired(); 319 actionsWithinTransactionCount++; 320 } 321 322 327 protected void renewTransactionIfRequired() throws IOException ,ClassNotFoundException ,TransactionException { 328 if (actionsWithinTransactionCount>=100) { completeTransaction(); 330 331 env.getLogWriter().newEntry(this,"toBeProcessedCount="+surelyReachableObjectsWhichHaveToBeMarkedAsSuch.size()+".",env.getLogWriter().DEBUG1); 332 333 } 334 335 if (transaction==null) { 336 transaction = env.getTransactionManager().newTransaction(env.getUserManager().getGarbageCollectorUser()); 337 } 338 } 339 340 343 protected void completeTransaction() throws IOException ,ClassNotFoundException { 344 if (transaction!=null) { 345 internalCompleteTransaction(transaction); 346 actionsWithinTransactionCount = 0; 347 env.getTransactionManager().deleteTransaction(); 348 transaction = null; 349 } 350 } 351 352 353 protected void internalCompleteTransaction(Transaction transaction) throws IOException ,ClassNotFoundException { 354 boolean allright = false; 355 try { 356 transaction.prepareCommit(); 357 allright = true; 358 } finally { 359 if (!allright) { 360 internalAbortTransaction(transaction); 361 } 362 } 363 364 internalFinishTransaction(transaction); 365 } 366 367 protected void internalFinishTransaction(Transaction transaction) throws IOException ,ClassNotFoundException { 368 TransactionManager transactionManager = transaction.getManager(); 369 370 try { 371 transactionManager.beginExclusion(); 372 transaction.commit(); 373 } finally { 374 transactionManager.endExclusion(); 375 transactionManager.notifyWaitingTransactions(); 376 } 377 } 378 379 protected void internalAbortTransaction(Transaction transaction) throws IOException ,ClassNotFoundException { 380 TransactionManager transactionManager = transaction.getManager(); 381 try { 382 transactionManager.beginExclusion(); 383 transaction.abort(null); 384 } finally { 385 transactionManager.endExclusion(); 386 transactionManager.notifyWaitingTransactions(); 387 } 388 } 389 390 protected synchronized void setPhase(int to) { 391 phase = to; 392 env.getLogWriter().newEntry(this,"setPhase("+to+")",env.getLogWriter().DEBUG2); 393 } 394 395 protected synchronized void waitForPhase(int newPhase) throws InterruptedException { 396 while (phase!=newPhase) { 397 wait(); 398 } 399 } 400 401 protected void addRootSetElementsToSurelyReachableSet() { 402 startFilterDatabaseObjectReferencesAtExternalDatabaseGates(); 403 addAllNamedObjectsToSurelyReachableSet(); 404 } 405 406 407 protected void startFilterDatabaseObjectReferencesAtExternalDatabaseGates() { 408 env.getInvokeServer().startFilterDatabaseObjectReferencesExports(this); 409 env.getLocalClientTracker().startFilterDatabaseObjectReferencesExports(this); 410 } 411 412 public void notifyDatabaseObjectIsExported(ObjectID id) { 413 notifyDatabaseObjectIsAboutToBeExported(id); 414 } 415 416 420 public void notifyDatabaseObjectIsAboutToBeExported(ObjectID id) { 421 ensureSurelyReachable(id); 423 } 424 425 428 protected void addAllNamedObjectsToSurelyReachableSet() { 429 env.getStoreManager().reportNamedObjectsToGarbageCollector(); 430 } 431 432 436 public void notifyNamedObject(ObjectID id) { 437 ensureSurelyReachable(id); 438 } 439 440 444 public void notifyNewObjectName(ObjectContainer objectContainer) { 445 ensureSurelyReachable(objectContainer); 446 } 447 448 451 public void notifyNewObjectContainer(ObjectContainer objectContainer) { 452 ensureDoneReachable(objectContainer); 453 } 454 455 459 protected void ensureSurelyReachable(ObjectID id) { 460 synchronized (this) { 461 if (isRunning()) { 462 addObjectIDToSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(id); 463 } 464 } 465 } 466 467 470 protected void addObjectIDToSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(ObjectID id) { 471 synchronized (surelyReachableObjectsWhichHaveToBeMarkedAsSuch) { 472 surelyReachableObjectsWhichHaveToBeMarkedAsSuch.push(id); 474 } 475 } 476 477 481 protected void ensureSurelyReachable(ObjectContainer objectContainer) { 482 487 addObjectIDToSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(objectContainer.id()); 488 } 489 490 494 protected boolean isRunning() { 495 return phase!=PHASE_IDLE; 496 } 497 498 501 protected void processSurelyReachableObjectsWhichHaveToBeMarkedAsSuch() { 502 ObjectID id; 503 504 int surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize = -1; 505 506 retryLoop: 507 for (;;) { 508 for (;;) { 509 if (kill) { 510 break retryLoop; 511 } 512 synchronized (surelyReachableObjectsWhichHaveToBeMarkedAsSuch) { 513 id = (ObjectID) surelyReachableObjectsWhichHaveToBeMarkedAsSuch.pop(); 514 } 515 516 if (id==null) { 517 break; 518 } 519 520 try { 521 526 527 notifyAboutTransactionActionAndRenewTransactionIfRequired(); 529 530 532 ObjectContainer container = transaction.acquireObject(id,Lock.LEVEL_READ); 533 534 processObjectContainerWhichWantsToBeSurelyReachable(transaction,container); 535 } catch (ObjectNotFoundException e) { 537 } catch (ClassNotFoundException e) { 538 } catch (IOException e) { 539 } catch (TransactionException e) { 541 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 542 } 544 } 545 546 boolean waitRecommended; 547 548 synchronized (surelyReachableObjectsWhichHaveToBeMarkedAsSuch) { 549 waitRecommended = surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize==surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.size(); 550 551 surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize = surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.size(); 552 553 while (!surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.isEmpty()) { 554 surelyReachableObjectsWhichHaveToBeMarkedAsSuch.push(surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.getFirst()); 555 } 556 } 557 558 if (surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize>0) { 559 if (waitRecommended) { 560 try { 561 try { 562 completeTransaction(); } catch (ClassNotFoundException e) { 564 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 565 } catch (IOException e) { 566 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 567 } 568 569 Thread.sleep(100+2000/(surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize)); 571 } catch (InterruptedException e) { 572 } 573 } 574 } else { 575 break; 576 } 577 } 578 579 try { 580 completeTransaction(); 581 } catch (ClassNotFoundException e) { 582 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 583 } catch (IOException e) { 584 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 585 } 586 } 588 589 597 protected int internalEnsureSurelyReachable(ObjectContainer objectContainer) { 598 synchronized (garbageCollectionLevelsLock) { 599 return objectContainer.ensureGarbageCollectionLevel(currentGarbageCollectionLevel); 600 } 601 } 602 603 606 protected void ensureDoneReachable(ObjectContainer objectContainer) { 607 internalEnsureDoneReachable(objectContainer); 608 } 609 610 613 protected void internalEnsureDoneReachable(ObjectContainer objectContainer) { 614 synchronized (garbageCollectionLevelsLock) { 615 objectContainer.ensureGarbageCollectionLevel(doneReachableGarbageCollectionLevel); 616 } 617 } 618 619 620 627 protected void processObjectContainerWhichWantsToBeSurelyReachable(Transaction transaction,ObjectContainer objectContainer) { 628 try { 629 int difference = internalEnsureSurelyReachable(objectContainer); 630 631 633 if (difference<=0) { 634 processReferencesByThisObject(transaction,objectContainer); 635 } 636 } finally { 637 objectContainer.unpin(); 638 } 639 } 640 641 648 protected void processReferencesByThisObject(Transaction transaction,ObjectContainer objectContainer) { 649 653 654 673 int previousLockLevel = objectContainer.lock().tryAcquire(transaction,Lock.LEVEL_WRITE); 675 676 if (previousLockLevel!=Lock.NOT_ACQUIRED) { 677 try { 678 env.getStoreManager().updateLockLevel(transaction,objectContainer); 679 GarbageCollectorProxyObjectIdentificationObjectOutputStream identificator = new GarbageCollectorProxyObjectIdentificationObjectOutputStream(); 680 681 identificator.identifyProxys(objectContainer); 682 683 internalEnsureDoneReachable(objectContainer); 684 } catch (IOException e) { 685 throw new RuntimeException ("Caught during serialization for proxy object identification: "+e); 688 } finally { 689 } 692 } else { 693 deferProcessingOfObjectContainerDueToLockContention(objectContainer); 694 } 695 } 696 697 704 protected void deferProcessingOfObjectContainerDueToLockContention(ObjectContainer objectContainer) { 705 synchronized (surelyReachableObjectsWhichHaveToBeMarkedAsSuch) { 706 surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.add(objectContainer.id()); 707 } 708 } 709 710 716 public void interceptInvocationPre(Transaction transaction,ObjectContainer callee,Object [] args) { 717 718 732 if (isRunning()) { 733 SimpleArrayList callStack = transaction.getCallStack(); 734 735 try { 736 if (args!=null) { 737 ObjectContainer caller = (ObjectContainer) callStack.peek(); 738 739 if (caller!=null) { 740 741 749 if (false) { 750 755 checkForPossibleOzoneProxys: 756 for (;;) { 757 for (int i = args.length-1;i>=0;i--) { 758 if (args[i] instanceof OzoneProxy) { 759 break checkForPossibleOzoneProxys; 760 } 761 } 762 return; 763 } 764 } 765 766 boolean possibleProxyBorderCross = false; 767 768 synchronized (garbageCollectionLevelsLock) { 769 if (callee.getGarbageCollectionLevel()==doneReachableGarbageCollectionLevel) { if (caller.getGarbageCollectionLevel()!=doneReachableGarbageCollectionLevel) { possibleProxyBorderCross = true; 773 } 774 } 775 } 776 777 if (possibleProxyBorderCross) { 778 for (int i = args.length-1;i>=0;i--) { 779 checkForProxyBorderCross(args[i]); 780 } 781 } 782 } 783 } 784 } finally { 785 callStack.push(callee); 786 } 787 } 788 } 789 790 796 public void interceptInvocationPost(Transaction transaction,ObjectContainer callee,Object result) { 797 811 if (isRunning()) { 812 SimpleArrayList callStack = transaction.getCallStack(); 813 814 if (result!=null) { 815 ObjectContainer caller = (ObjectContainer) callStack.peek(); 816 817 if (caller!=null) { 818 if (result instanceof OzoneCompatibleOrProxy) { 819 821 boolean possibleProxyBorderCross = false; 822 823 synchronized (garbageCollectionLevelsLock) { 824 if (caller.getGarbageCollectionLevel()==doneReachableGarbageCollectionLevel) { if (callee.getGarbageCollectionLevel()!=doneReachableGarbageCollectionLevel) { possibleProxyBorderCross = true; 828 } 829 } 830 } 831 832 if (possibleProxyBorderCross) { 833 if (result instanceof OzoneCompatible) { 834 checkForProxyBorderCross((OzoneCompatible) result); 835 } else { checkForProxyBorderCross((OzoneProxy) result); 837 } 838 } 839 } 840 } 841 } 842 callStack.pop(); 843 } 844 } 845 846 851 protected void checkForProxyBorderCross(Object o) { 852 if (o instanceof OzoneProxy) { 853 checkForProxyBorderCross((OzoneProxy) o); 854 } 855 } 856 857 862 protected void checkForProxyBorderCross(OzoneProxy o) { 863 ObjectID id = o.remoteID(); 864 865 addObjectIDToSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(id); 866 } 867 868 873 protected void checkForProxyBorderCross(OzoneCompatible o) { 874 ensureSurelyReachable(o.container().id()); 876 } 877 878 883 public class GarbageCollectorProxyObjectIdentificationObjectOutputStream extends ObjectOutputStream { 884 891 892 protected GarbageCollectorProxyObjectIdentificationObjectOutputStream() throws IOException { 893 super(NullOutputStream.getDefault()); 894 } 895 896 public void notifyOzoneProxyEncountered(OzoneProxy encounteredProxy) { 897 addObjectIDToSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(encounteredProxy.remoteID()); 898 } 899 900 protected void identifyProxys(ObjectContainer objectContainer) throws IOException { 901 writeObject(objectContainer.target()); 902 } 903 } 904 905 908 protected void sweepUnreachableObjects() { 909 env.getLogWriter().newEntry(this,"sweepUnreachableObjects(): starting to sweep...",env.getLogWriter().DEBUG3); 910 911 DxIterator i = env.getStoreManager().objectIDIterator(); 912 913 while (i.next()!=null) { 914 if (kill) { 915 break; 916 } 917 918 ObjectID id = (ObjectID) i.key(); 919 try { 920 notifyAboutTransactionActionAndRenewTransactionIfRequired(); 921 922 ObjectContainer container = transaction.acquireObject(id,Lock.LEVEL_READ); 923 924 try { 925 synchronized (garbageCollectionLevelsLock) { 926 928 if (container.getGarbageCollectionLevel()-currentGarbageCollectionLevel<0) { 929 env.getLogWriter().newEntry(this,"sweepUnreachableObjects(): deleting "+id,env.getLogWriter().DEBUG3); 930 931 transaction.deleteObject(id); 932 } 933 } 934 } finally { 935 transaction.releaseObject(container); 936 } 937 } catch (ObjectNotFoundException e) { 938 env.getLogWriter().newEntry(this,"caught while sweeping: ",e,env.getLogWriter().DEBUG3); 939 } catch (ClassNotFoundException e) { 940 env.getLogWriter().newEntry(this,"caught while sweeping: ",e,env.getLogWriter().DEBUG3); 941 } catch (IOException e) { 942 env.getLogWriter().newEntry(this,"caught while sweeping: ",e,env.getLogWriter().DEBUG3); 944 } catch (TransactionException e) { 945 env.getLogWriter().newEntry(this,"caught while sweeping: ",e,env.getLogWriter().ERROR); 947 } catch (OzoneInternalException e) { 948 env.getLogWriter().newEntry(this,"caught while sweeping: ",e,env.getLogWriter().ERROR); 949 } catch (OzoneRemoteException e) { 950 env.getLogWriter().newEntry(this,"caught while sweeping: ",e,env.getLogWriter().ERROR); 951 } 952 } 953 try { 954 completeTransaction(); 955 } catch (ClassNotFoundException e) { 956 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 957 } catch (IOException e) { 958 env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR); 959 } 960 } 961 } 962 | Popular Tags |