package com.sleepycat.je.dbi;
import com.sleepycat.je.latch.Latch;
import com.sleepycat.je.latch.LatchSupport;
public class INList {
private Set addedINs=null;
private Latch majorLatch;
private Latch minorLatch;
/**
* The locking hierarchy is:
* 1. INList major latch.
* 2. IN latch.
* In other words, the INList major latch must be taken before any IN
* latches to avoid deadlock.
*/
public void latchMajor() throws DatabaseException {
assert LatchSupport.countLatchesHeld() == 0;
majorLatch.acquire();
}
public void releaseMajorLatchIfHeld() throws DatabaseException {
if (majorLatch.isOwner()) {
releaseMajorLatch();
}
}
public void releaseMajorLatch() throws DatabaseException {
latchMinorAndDumpAddedINs();
majorLatch.release();
}
private void dumpAddedINsIntoMajorSet(){
if (addedINs.size() > 0) {
ins.addAll(addedINs);
addedINs.clear();
}
}
void latchMinorAndDumpAddedINs() throws DatabaseException {
latchMinor();
try {
dumpAddedINsIntoMajorSet();
}
finally {
releaseMinorLatch();
}
}
private void latchMinor() throws DatabaseException {
minorLatch.acquire();
}
private void releaseMinorLatch() throws DatabaseException {
minorLatch.release();
}
protected void hook338( EnvironmentImpl envImpl){
addedINs=new HashSet();
majorLatch=LatchSupport.makeLatch(DEBUG_NAME + " Major Latch",envImpl);
minorLatch=LatchSupport.makeLatch(DEBUG_NAME + " Minor Latch",envImpl);
original(envImpl);
}
protected void hook339( EnvironmentImpl envImpl) throws DatabaseException {
majorLatch=LatchSupport.makeLatch(DEBUG_NAME + " Major Latch",envImpl);
minorLatch=LatchSupport.makeLatch(DEBUG_NAME + " Minor Latch",envImpl);
original(envImpl);
}
protected void hook340() throws DatabaseException {
addedINs=new HashSet();
original();
}
/**
* An IN is getting evicted or is displaced by recovery. Caller is
* responsible for acquiring the major latch before calling this and
* releasing it when they're done.
*/
public void removeLatchAlreadyHeld( IN in) throws DatabaseException {
assert majorLatch.isOwner();
original(in);
}
protected boolean hook341( IN in, boolean removeDone) throws DatabaseException {
if (!removeDone) {
minorLatch.acquire();
try {
removeDone=addedINs.remove(in);
dumpAddedINsIntoMajorSet();
}
finally {
minorLatch.release();
}
}
return original(in,removeDone);
}
/**
* An IN is getting swept or is displaced by recovery.
*/
public void remove( IN in) throws DatabaseException {
assert LatchSupport.countLatchesHeld() == 0;
majorLatch.acquire();
try {
original(in);
}
finally {
releaseMajorLatch();
}
}
public SortedSet tailSet( IN in) throws DatabaseException {
assert majorLatch.isOwner();
return original(in);
}
public IN first() throws DatabaseException {
assert majorLatch.isOwner();
return original();
}
/**
* Return an iterator over the main 'ins' set. Returned iterator will not
* show the elements in addedINs.
* The major latch should be held before entering. The caller is
* responsible for releasing the major latch when they're finished with the
* iterator.
* @return an iterator over the main 'ins' set.
*/
public Iterator iterator(){
assert majorLatch.isOwner();
return original();
}
/**
* Clear the entire list during recovery and at shutdown.
*/
public void clear() throws DatabaseException {
assert LatchSupport.countLatchesHeld() == 0;
majorLatch.acquire();
minorLatch.acquire();
original();
}
protected void hook342() throws DatabaseException {
addedINs.clear();
minorLatch.release();
releaseMajorLatch();
original();
}
@MethodObject static class INList_add {
protected void hook343() throws DatabaseException {
try {
original();
}
finally {
if (addToMajor) {
_this.releaseMajorLatchIfHeld();
}
}
}
protected void hook344() throws DatabaseException {
enteredWithLatchHeld=_this.majorLatch.isOwner();
original();
}
protected void hook345() throws DatabaseException {
if (enteredWithLatchHeld) {
addToMajor=false;
}
else {
if (!(_this.majorLatch.acquireNoWait())) {
addToMajor=false;
}
}
if (addToMajor) {
original();
}
else {
_this.minorLatch.acquire();
try {
_this.addAndSetMemory(_this.addedINs,in);
}
finally {
_this.minorLatch.release();
}
if (!enteredWithLatchHeld) {
if (_this.majorLatch.acquireNoWait()) {
try {
_this.latchMinorAndDumpAddedINs();
}
finally {
_this.releaseMajorLatch();
}
}
}
}
}
}
}