📄 garbagecollector.java
字号:
/**
Checks wether the current transaction has to be committed (because it accumulated too much changes)
and if so, commits it and closes it. Afterwards (or if there has not been a current transaction already),
it creates a new current transaction.
*/
protected void renewTransactionIfRequired() throws IOException,ClassNotFoundException,TransactionException {
if (actionsWithinTransactionCount>=100) { // We renew if we had 100 or more actions within this transaction.
completeTransaction();
env.getLogWriter().newEntry(this,"toBeProcessedCount="+surelyReachableObjectsWhichHaveToBeMarkedAsSuch.size()+".",env.getLogWriter().DEBUG1);
}
if (transaction==null) {
transaction = env.getTransactionManager().newTransaction(env.getUserManager().getGarbageCollectorUser());
}
}
/**
Completes the current transaction and releases it.
*/
protected void completeTransaction() throws IOException,ClassNotFoundException {
if (transaction!=null) {
internalCompleteTransaction(transaction);
actionsWithinTransactionCount = 0;
env.getTransactionManager().deleteTransaction();
transaction = null;
}
}
protected void internalCompleteTransaction(Transaction transaction) throws IOException,ClassNotFoundException {
boolean allright = false;
try {
transaction.prepareCommit();
allright = true;
} finally {
if (!allright) {
internalAbortTransaction(transaction);
}
}
internalFinishTransaction(transaction);
}
protected void internalFinishTransaction(Transaction transaction) throws IOException,ClassNotFoundException {
TransactionManager transactionManager = transaction.getManager();
try {
transactionManager.beginExclusion();
transaction.commit();
} finally {
transactionManager.endExclusion();
transactionManager.notifyWaitingTransactions();
}
}
protected void internalAbortTransaction(Transaction transaction) throws IOException,ClassNotFoundException {
TransactionManager transactionManager = transaction.getManager();
try {
transactionManager.beginExclusion();
transaction.abort(null);
} finally {
transactionManager.endExclusion();
transactionManager.notifyWaitingTransactions();
}
}
protected synchronized void setPhase(int to) {
phase = to;
env.getLogWriter().newEntry(this,"setPhase("+to+")",env.getLogWriter().DEBUG2);
}
protected synchronized void waitForPhase(int newPhase) throws InterruptedException {
while (phase!=newPhase) {
wait();
}
}
protected void addRootSetElementsToSurelyReachableSet() {
startFilterDatabaseObjectReferencesAtExternalDatabaseGates();
addAllNamedObjectsToSurelyReachableSet();
}
protected void startFilterDatabaseObjectReferencesAtExternalDatabaseGates() {
env.getInvokeServer().startFilterDatabaseObjectReferencesExports(this);
env.getLocalClientTracker().startFilterDatabaseObjectReferencesExports(this);
}
public void notifyDatabaseObjectIsExported(ObjectID id) {
notifyDatabaseObjectIsAboutToBeExported(id);
}
/**
This method is called by DbInvokeClient to notify this garbageCollector
that there is a reference which is to be exported to a client.
*/
public void notifyDatabaseObjectIsAboutToBeExported(ObjectID id) {
// These object referenced belong, because they are used, to the surelyReachable set.
ensureSurelyReachable(id);
}
/**
This method walks through all named objects and adds each of them to the surelyReachable set.
*/
protected void addAllNamedObjectsToSurelyReachableSet() {
env.getStoreManager().reportNamedObjectsToGarbageCollector();
}
/**
This method is called by StoreManager to indicate that the object
with the given id is a named object.
*/
public void notifyNamedObject(ObjectID id) {
ensureSurelyReachable(id);
}
/**
This method is called by StoreManager in the event an unnamed object receives a name.
This is the case if an object which was formerly unnamed gets a name.
*/
public void notifyNewObjectName(ObjectContainer objectContainer) {
ensureSurelyReachable(objectContainer);
}
/**
This method is called by StoreManager in the event an object is freshly created.
*/
public void notifyNewObjectContainer(/*Transaction transaction,*/ObjectContainer objectContainer) {
ensureDoneReachable(/*transaction,*/objectContainer);
}
/**
Calling this method makes sure that the object which is referenced by the given ID is
at least surely reachable.
*/
protected void ensureSurelyReachable(ObjectID id) {
synchronized (this) {
if (isRunning()) {
addObjectIDToSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(id);
}
}
}
/**
This method may be called both from transaction threads and from GarbageCollector-Threads.
*/
protected void addObjectIDToSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(ObjectID id) {
synchronized (surelyReachableObjectsWhichHaveToBeMarkedAsSuch) {
// env.getLogWriter().newEntry(this,"addObjectID(): adding "+id+".",new Exception(),env.getLogWriter().DEBUG3);
surelyReachableObjectsWhichHaveToBeMarkedAsSuch.push(id);
}
}
/**
Calling this method makes sure that the object which is referenced by the given ID is
at least surely reachable. This method is called by non-GarbageCollector-Threads.
*/
protected void ensureSurelyReachable(ObjectContainer objectContainer) {
// This is not possible because processing has to be done within a GarbageCollector transaction and not within any other transaction.
/*
objectContainer.pin();
processObjectContainerWhichWantsToBeSurelyReachable(objectContainer);
*/
addObjectIDToSurelyReachableObjectsWhichHaveToBeMarkedAsSuch(objectContainer.id());
}
/**
Returns wether this GarbageCollector is running. This method
must be called during synchronization on this GarbageCollector.
*/
protected boolean isRunning() {
return phase!=PHASE_IDLE;
}
/**
This is the "main()" method of the mark phase.
*/
protected void processSurelyReachableObjectsWhichHaveToBeMarkedAsSuch() {
ObjectID id;
int surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize = -1;
retryLoop:
for (;;) {
for (;;) {
if (kill) {
break retryLoop;
}
synchronized (surelyReachableObjectsWhichHaveToBeMarkedAsSuch) {
id = (ObjectID) surelyReachableObjectsWhichHaveToBeMarkedAsSuch.pop();
}
if (id==null) {
break;
}
try {
/*
ObjectContainer container = env.getStoreManager().containerForID(null,id);
processObjectContainerWhichWantsToBeSurelyReachable(container);
*/
// We should acquire the container via our transaction
notifyAboutTransactionActionAndRenewTransactionIfRequired();
// env.getLogWriter().newEntry(this,"process(): processing "+id+".",env.getLogWriter().DEBUG3);
ObjectContainer container = transaction.acquireObject(id,Lock.LEVEL_READ);
processObjectContainerWhichWantsToBeSurelyReachable(transaction,container);
// } catch (ObjNotFoundException e) {
} catch (ObjectNotFoundException e) {
} catch (ClassNotFoundException e) {
} catch (IOException e) {
// It does not matter if the object is gone in the meantime. This is the best case for a garbage collector :-)
} catch (TransactionException e) {
env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR);
// FIXME. What do we in this case?
}
}
boolean waitRecommended;
synchronized (surelyReachableObjectsWhichHaveToBeMarkedAsSuch) {
waitRecommended = surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize==surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.size();
surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize = surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.size();
while (!surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.isEmpty()) {
surelyReachableObjectsWhichHaveToBeMarkedAsSuch.push(surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContented.getFirst());
}
}
if (surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize>0) {
if (waitRecommended) {
try {
try {
completeTransaction(); // We should finish our transaction so that other transactions may complete.
} catch (ClassNotFoundException e) {
env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR);
} catch (IOException e) {
env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR);
}
// We're waiting less if there are more lock-contented objects, but at least 100ms
Thread.sleep(100+2000/(surelyReachableObjectsWhichShouldHaveBeenProcessedButWereLockContentedSize));
} catch (InterruptedException e) {
}
}
} else {
break;
}
}
try {
completeTransaction();
} catch (ClassNotFoundException e) {
env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR);
} catch (IOException e) {
env.getLogWriter().newEntry(this,"caught: ",e,env.getLogWriter().ERROR);
}
// Pheew. We're done. Now sweep the unreachable objects.
}
/**
Internally ensures that the given object is at least surelyReachable.
@return
<0 if this object has been updated. If this is the case, this object has to join a transaction which will complete successfully.
=0 if this object has not been updated, it is surelyReachable
>0 if this object has not been updated, it is processedReachable
*/
protected int internalEnsureSurelyReachable(ObjectContainer objectContainer) {
synchronized (garbageCollectionLevelsLock) {
return objectContainer.ensureGarbageCollectionLevel(currentGarbageCollectionLevel);
}
}
/**
Ensures that the given object is doneReachable.
*/
protected void ensureDoneReachable(/*Transaction transaction,*/ObjectContainer objectContainer) {
internalEnsureDoneReachable(objectContainer);
}
/**
Internally ensures that the given object is doneReachable.
*/
protected void internalEnsureDoneReachable(ObjectContainer objectContainer) {
synchronized (garbageCollectionLevelsLock) {
objectContainer.ensureGarbageCollectionLevel(doneReachableGarbageCollectionLevel);
}
}
/**
* Processes an ObjectContainer which possibly has not already been registered as surely reachable.
* This method may be called only by the garbage collector thread.
*
* @param transaction
* @param objectContainer
*/
protected void processObjectContainerWhichWantsToBeSurelyReachable(Transaction transaction,ObjectContainer objectContainer) {
try {
int difference = internalEnsureSurelyReachable(objectContainer);
// env.getLogWriter().newEntry(this,"processObjectContainerWhichWantsToBeSurelyReachable("+objectContainer+"), difference="+difference+".",env.getLogWriter().DEBUG3);
if (difference<=0) {
processReferencesByThisObject(transaction,objectContainer);
}
} finally {
objectContainer.unpin();
}
}
/**
Determines all references which are "contained" within the given object,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -