Fixed rare race condition in ActiveSectionTracker, occured more frequently with high core systems. This is hopefully the last concurrency bug in the tracker
This commit is contained in:
@@ -113,6 +113,10 @@ public class ActiveSectionTracker {
|
|||||||
long stamp = this.lruLock.writeLock();
|
long stamp = this.lruLock.writeLock();
|
||||||
section = this.lruSecondaryCache.remove(key);
|
section = this.lruSecondaryCache.remove(key);
|
||||||
this.lruLock.unlockWrite(stamp);
|
this.lruLock.unlockWrite(stamp);
|
||||||
|
if (section != null) {
|
||||||
|
section.primeForReuse();
|
||||||
|
section.acquire(1);
|
||||||
|
}
|
||||||
lock.unlockRead(stamp2);
|
lock.unlockRead(stamp2);
|
||||||
} else {
|
} else {
|
||||||
VolatileHolder.PRE_ACQUIRE_COUNT.getAndAdd(holder, 1);
|
VolatileHolder.PRE_ACQUIRE_COUNT.getAndAdd(holder, 1);
|
||||||
@@ -142,11 +146,10 @@ public class ActiveSectionTracker {
|
|||||||
//We need to set the data to air as it is undefined state
|
//We need to set the data to air as it is undefined state
|
||||||
Arrays.fill(section.data, 0);
|
Arrays.fill(section.data, 0);
|
||||||
}
|
}
|
||||||
} else {
|
section.acquire(1);
|
||||||
section.primeForReuse();
|
|
||||||
}
|
}
|
||||||
int preAcquireCount = (int) VolatileHolder.PRE_ACQUIRE_COUNT.getAndSet(holder, 0);
|
int preAcquireCount = (int) VolatileHolder.PRE_ACQUIRE_COUNT.getAndSet(holder, 0);
|
||||||
section.acquire(preAcquireCount+1);//pre acquire amount
|
section.acquire(preAcquireCount);//pre acquire amount
|
||||||
VolatileHolder.POST_ACQUIRE_COUNT.set(holder, preAcquireCount);
|
VolatileHolder.POST_ACQUIRE_COUNT.set(holder, preAcquireCount);
|
||||||
|
|
||||||
//TODO: mark if the section was loaded null
|
//TODO: mark if the section was loaded null
|
||||||
@@ -223,7 +226,7 @@ public class ActiveSectionTracker {
|
|||||||
var cached = cache.remove(section.key);
|
var cached = cache.remove(section.key);
|
||||||
var obj = cached.obj;
|
var obj = cached.obj;
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
throw new IllegalStateException("This should be impossible: " + WorldEngine.pprintPos(section.key));
|
throw new IllegalStateException("This should be impossible: " + WorldEngine.pprintPos(section.key) + " secObj: " + System.identityHashCode(section));
|
||||||
}
|
}
|
||||||
if (obj != section) {
|
if (obj != section) {
|
||||||
throw new IllegalStateException("Removed section not the same as the referenced section in the cache: cached: " + obj + " got: " + section + " A: " + WorldSection.ATOMIC_STATE_HANDLE.get(obj) + " B: " +WorldSection.ATOMIC_STATE_HANDLE.get(section));
|
throw new IllegalStateException("Removed section not the same as the referenced section in the cache: cached: " + obj + " got: " + section + " A: " + WorldSection.ATOMIC_STATE_HANDLE.get(obj) + " B: " +WorldSection.ATOMIC_STATE_HANDLE.get(section));
|
||||||
@@ -235,6 +238,7 @@ public class ActiveSectionTracker {
|
|||||||
WorldSection aa = null;
|
WorldSection aa = null;
|
||||||
if (sec != null) {
|
if (sec != null) {
|
||||||
long stamp2 = this.lruLock.writeLock();
|
long stamp2 = this.lruLock.writeLock();
|
||||||
|
lock.unlockWrite(stamp);
|
||||||
WorldSection a = this.lruSecondaryCache.put(section.key, section);
|
WorldSection a = this.lruSecondaryCache.put(section.key, section);
|
||||||
if (a != null) {
|
if (a != null) {
|
||||||
throw new IllegalStateException("duplicate sections in cache is impossible");
|
throw new IllegalStateException("duplicate sections in cache is impossible");
|
||||||
@@ -245,9 +249,10 @@ public class ActiveSectionTracker {
|
|||||||
}
|
}
|
||||||
this.lruLock.unlockWrite(stamp2);
|
this.lruLock.unlockWrite(stamp2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
lock.unlockWrite(stamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
lock.unlockWrite(stamp);
|
|
||||||
|
|
||||||
if (aa != null) {
|
if (aa != null) {
|
||||||
aa._releaseArray();
|
aa._releaseArray();
|
||||||
@@ -276,16 +281,45 @@ public class ActiveSectionTracker {
|
|||||||
return this.lruSecondaryCache.size();
|
return this.lruSecondaryCache.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws InterruptedException {
|
||||||
var tracker = new ActiveSectionTracker(1, a->0, 1<<10);
|
var tracker = new ActiveSectionTracker(6, a->0, 2<<10);
|
||||||
|
var bean = tracker.acquire(0, 0, 0, 9, false);
|
||||||
var section = tracker.acquire(0,0,0,0, false);
|
var bean2 = tracker.acquire(1, 0, 0, 0, false);
|
||||||
|
System.out.println("Target obj:" + System.identityHashCode(bean2));
|
||||||
|
bean2.release();
|
||||||
|
Thread[] ts = new Thread[10];
|
||||||
|
for (int i = 0; i < ts.length;i++) {
|
||||||
|
int tid = i;
|
||||||
|
ts[i] = new Thread(()->{
|
||||||
|
try {
|
||||||
|
for (int j = 0; j < 5000; j++) {
|
||||||
|
if (true) {
|
||||||
|
var section = tracker.acquire(0, 0, 0, 0, false);
|
||||||
section.acquire();
|
section.acquire();
|
||||||
var section2 = tracker.acquire(0,0,0,0, false);
|
var section2 = tracker.acquire(1, 0, 0, 0, false);
|
||||||
section.release();
|
section.release();
|
||||||
section.release();
|
section.release();
|
||||||
section = tracker.acquire(0,0,0,0, false);
|
section2.release();
|
||||||
section.release();
|
}
|
||||||
|
if (true) {
|
||||||
|
|
||||||
|
var section = tracker.acquire(0, 0, 0, 0, false);
|
||||||
|
var section2 = tracker.acquire(1, 0, 0, 0, false);
|
||||||
|
section2.release();
|
||||||
|
section.release();
|
||||||
|
}
|
||||||
|
if (true) {
|
||||||
|
tracker.acquire(1, 0, 0, 0, false).release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Thread " + tid, e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ts[i].start();
|
||||||
|
}
|
||||||
|
for (var t : ts) {
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ public final class WorldSection {
|
|||||||
public int acquire(int count) {
|
public int acquire(int count) {
|
||||||
int state = ((int) ATOMIC_STATE_HANDLE.getAndAdd(this, count<<1)) + (count<<1);
|
int state = ((int) ATOMIC_STATE_HANDLE.getAndAdd(this, count<<1)) + (count<<1);
|
||||||
if ((state & 1) == 0) {
|
if ((state & 1) == 0) {
|
||||||
throw new IllegalStateException("Tried to acquire unloaded section: " + WorldEngine.pprintPos(this.key));
|
throw new IllegalStateException("Tried to acquire unloaded section: " + WorldEngine.pprintPos(this.key) + " obj: " + System.identityHashCode(this));
|
||||||
}
|
}
|
||||||
return state>>1;
|
return state>>1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user