add cache of size 1 inside of DatasetLockCache
pass the number of arenas to the ArenaManagers
clean up assignment of RecordManagers to threads
change allocation policy in RecordManagers
extract contruction of "Global" pointers
split debug options into TRACK_ALLOC_ID, TRACK_ALLOC_LOC, and CHECK_SLOTS
diff --git a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordType.java b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordType.java
index 6d31f63..2ffa8be 100644
--- a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordType.java
+++ b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordType.java
@@ -110,7 +110,7 @@
.append("(long slotNum) {\n");
if (initial != null) {
sb = indent(sb, indent, level + 1);
- sb.append("if (TRACK_ALLOC) checkSlot(slotNum);\n");
+ sb.append("if (TRACK_ALLOC_ID) checkAllocId(slotNum);\n");
}
sb = indent(sb, indent, level + 1);
sb.append("final int arenaId = RecordManagerTypes.Global.arenaId(slotNum);\n");
@@ -134,7 +134,7 @@
.append(" value) {\n");
if (initial != null) {
sb = indent(sb, indent, level + 1);
- sb.append("if (TRACK_ALLOC) checkSlot(slotNum);\n");
+ sb.append("if (TRACK_ALLOC_ID) checkAllocId(slotNum);\n");
}
sb = indent(sb, indent, level + 1);
sb.append("final int arenaId = RecordManagerTypes.Global.arenaId(slotNum);\n");
diff --git a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/resources/ArenaManager.java b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/resources/ArenaManager.java
index 58f8972..6d77b51 100644
--- a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/resources/ArenaManager.java
+++ b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/resources/ArenaManager.java
@@ -15,73 +15,67 @@
package edu.uci.ics.asterix.transaction.management.service.locking;
-import java.util.ArrayList;
-
import edu.uci.ics.asterix.transaction.management.service.locking.AllocInfo;
import edu.uci.ics.asterix.transaction.management.service.locking.RecordManagerTypes;
public class @E@ArenaManager {
- public static final boolean TRACK_ALLOC = @DEBUG@;
+ public static final boolean TRACK_ALLOC_ID = @DEBUG@;
private final int noArenas;
- private final long txnShrinkTimer;
- private ArrayList<@E@RecordManager> arenas;
- private volatile int nextArena;
- private ThreadLocal<LocalManager> local;
+ private final @E@RecordManager[] arenas;
+ private ThreadLocal<LocalManager> local;
- public @E@ArenaManager(long txnShrinkTimer) {
- this.txnShrinkTimer = txnShrinkTimer;
- noArenas = Runtime.getRuntime().availableProcessors() * 2;
- arenas = new ArrayList<@E@RecordManager>(noArenas);
- nextArena = 0;
+ static class LocalManager {
+ int arenaId;
+ @E@RecordManager mgr;
+ }
+
+ public @E@ArenaManager(final int noArenas, final long txnShrinkTimer) {
+ this.noArenas = noArenas;
+ arenas = new @E@RecordManager[noArenas];
+ for (int i = 0; i < noArenas; ++i) {
+ arenas[i] = new @E@RecordManager(txnShrinkTimer);
+ }
local = new ThreadLocal<LocalManager>() {
+ private int nextArena = 0;
+
@Override
- protected LocalManager initialValue() {
- return getNext();
+ protected synchronized LocalManager initialValue() {
+ @E@RecordManager mgr = arenas[nextArena];
+ LocalManager res = new LocalManager();
+ res.mgr = mgr;
+ res.arenaId = nextArena;
+ nextArena = (nextArena + 1) % noArenas;
+ return res;
}
};
}
public long allocate() {
final LocalManager localManager = local.get();
- long result = localManager.arenaId;
- result = result << 48;
- final int localId = localManager.mgr.allocate();
- result |= localId;
- if (TRACK_ALLOC) {
- final long allocId = (++localManager.mgr.allocCounter % 0x7fff);
- result |= (allocId << 32);
- setAllocId(result, (short) allocId);
- assert RecordManagerTypes.Global.allocId(result) == allocId;
- }
+ final @E@RecordManager recMgr = localManager.mgr;
+ final int allocId = TRACK_ALLOC_ID ? (++recMgr.allocCounter % 0x7fff) : 0;
+ final int localId = recMgr.allocate();
+
+ long result = RecordManagerTypes.Global.build(localManager.arenaId, allocId, localId);
+
+ if (TRACK_ALLOC_ID) setAllocId(result, (short) allocId);
+
+ assert RecordManagerTypes.Global.allocId(result) == allocId;
assert RecordManagerTypes.Global.arenaId(result) == localManager.arenaId;
assert RecordManagerTypes.Global.localId(result) == localId;
return result;
}
public void deallocate(long slotNum) {
- if (TRACK_ALLOC) {
- checkSlot(slotNum);
- }
+ if (TRACK_ALLOC_ID) checkAllocId(slotNum);
final int arenaId = RecordManagerTypes.Global.arenaId(slotNum);
get(arenaId).deallocate(RecordManagerTypes.Global.localId(slotNum));
}
- public synchronized LocalManager getNext() {
- if (nextArena >= arenas.size()) {
- arenas.add(new @E@RecordManager(txnShrinkTimer));
- }
- @E@RecordManager mgr = arenas.get(nextArena);
- LocalManager res = new LocalManager();
- res.mgr = mgr;
- res.arenaId = nextArena;
- nextArena = (nextArena + 1) % noArenas;
- return res;
- }
-
public @E@RecordManager get(int i) {
- return arenas.get(i);
+ return arenas[i];
}
public @E@RecordManager local() {
@@ -90,7 +84,7 @@
@METHODS@
- private void checkSlot(long slotNum) {
+ private void checkAllocId(long slotNum) {
final int refAllocId = RecordManagerTypes.Global.allocId(slotNum);
final short curAllocId = getAllocId(slotNum);
if (refAllocId != curAllocId) {
@@ -111,15 +105,10 @@
return get(arenaId).getAllocInfo(RecordManagerTypes.Global.localId(slotNum));
}
- static class LocalManager {
- int arenaId;
- @E@RecordManager mgr;
- }
-
public StringBuilder append(StringBuilder sb) {
- for (int i = 0; i < arenas.size(); ++i) {
+ for (int i = 0; i < noArenas; ++i) {
sb.append("++++ arena ").append(i).append(" ++++\n");
- arenas.get(i).append(sb);
+ arenas[i].append(sb);
}
return sb;
}
@@ -129,10 +118,9 @@
}
public Stats addTo(Stats s) {
- final int size = arenas.size();
- s.arenas += size;
- for (int i = 0; i < size; ++i) {
- arenas.get(i).addTo(s);
+ s.arenas += noArenas;
+ for (int i = 0; i < noArenas; ++i) {
+ arenas[i].addTo(s);
}
return s;
}
diff --git a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/resources/RecordManager.java b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/resources/RecordManager.java
index 01049d3..6aa26f4 100644
--- a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/resources/RecordManager.java
+++ b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/resources/RecordManager.java
@@ -23,7 +23,8 @@
public class @E@RecordManager {
- public static final boolean TRACK_ALLOC = @DEBUG@;
+ public static final boolean CHECK_SLOTS = @DEBUG@;
+ public static final boolean TRACK_ALLOC_LOC = @DEBUG@;
static final int NO_SLOTS = 10;
@@ -47,23 +48,39 @@
allocCounter = 0;
}
+ enum SlotSource {
+ NON_FULL,
+ UNINITIALIZED,
+ NEW
+ }
+
synchronized int allocate() {
if (buffers.get(current).isFull()) {
- int size = buffers.size();
- boolean needNewBuffer = true;
- for (int i = 0; i < size; i++) {
- Buffer buffer = buffers.get(i);
- if (! buffer.isInitialized()) {
- buffer.initialize();
+ final int size = buffers.size();
+ SlotSource source = SlotSource.NEW;
+ for (int i = 0; i < size; ++i) {
+ // If we find a buffer with space, we use it. Otherwise we
+ // remember the first uninitialized one and use that one.
+ final Buffer buffer = buffers.get(i);
+ if (buffer.isInitialized() && ! buffer.isFull()) {
+ source = SlotSource.NON_FULL;
current = i;
- needNewBuffer = false;
break;
+ } else if (! buffer.isInitialized() && source == SlotSource.NEW) {
+ source = SlotSource.UNINITIALIZED;
+ current = i;
}
}
-
- if (needNewBuffer) {
- buffers.add(new Buffer());
- current = buffers.size() - 1;
+
+ switch (source) {
+ case NEW:
+ buffers.add(new Buffer());
+ current = buffers.size() - 1;
+ break;
+ case UNINITIALIZED:
+ buffers.get(current).initialize();
+ case NON_FULL:
+ break;
}
}
++occupiedSlots;
@@ -202,9 +219,9 @@
}
static class Buffer {
- private ByteBuffer bb;
+ private ByteBuffer bb = null; // null represents 'deinitialized' state.
private int freeSlotNum;
- private int occupiedSlots = -1; //-1 represents 'deinitialized' state.
+ private int occupiedSlots;
ArrayList<AllocInfo> allocList;
@@ -222,7 +239,7 @@
}
setNextFreeSlot(NO_SLOTS - 1, -1); //-1 represents EOL(end of link)
- if (TRACK_ALLOC) {
+ if (TRACK_ALLOC_LOC) {
allocList = new ArrayList<AllocInfo>(NO_SLOTS);
for (int i = 0; i < NO_SLOTS; ++i) {
allocList.add(new AllocInfo());
@@ -231,16 +248,16 @@
}
public void deinitialize() {
+ if (TRACK_ALLOC_LOC) allocList = null;
bb = null;
- occupiedSlots = -1;
}
public boolean isInitialized() {
- return occupiedSlots >= 0;
+ return bb != null;
}
public boolean isFull() {
- return occupiedSlots == NO_SLOTS;
+ return freeSlotNum == -1;
}
public boolean isEmpty() {
@@ -252,7 +269,7 @@
freeSlotNum = getNextFreeSlot(slotNum);
@INIT_SLOT@
occupiedSlots++;
- if (TRACK_ALLOC) allocList.get(slotNum).alloc();
+ if (TRACK_ALLOC_LOC) allocList.get(slotNum).alloc();
return slotNum;
}
@@ -261,7 +278,7 @@
setNextFreeSlot(slotNum, freeSlotNum);
freeSlotNum = slotNum;
occupiedSlots--;
- if (TRACK_ALLOC) allocList.get(slotNum).free();
+ if (TRACK_ALLOC_LOC) allocList.get(slotNum).free();
}
public int getNextFreeSlot(int slotNum) {
@@ -293,7 +310,7 @@
}
private void checkSlot(int slotNum) {
- if (! TRACK_ALLOC) {
+ if (! CHECK_SLOTS) {
return;
}
final int itemOffset = (slotNum % NO_SLOTS) * ITEM_SIZE;
diff --git a/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/ConcurrentLockManager.java b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/ConcurrentLockManager.java
index 80da1ab..8a8194a 100644
--- a/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/ConcurrentLockManager.java
+++ b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/ConcurrentLockManager.java
@@ -76,9 +76,11 @@
final int lockManagerShrinkTimer = txnSubsystem.getTransactionProperties()
.getLockManagerShrinkTimer();
- resArenaMgr = new ResourceArenaManager(lockManagerShrinkTimer);
- reqArenaMgr = new RequestArenaManager(lockManagerShrinkTimer);
- jobArenaMgr = new JobArenaManager(lockManagerShrinkTimer);
+ int noArenas = Runtime.getRuntime().availableProcessors() * 2;
+
+ resArenaMgr = new ResourceArenaManager(noArenas, lockManagerShrinkTimer);
+ reqArenaMgr = new RequestArenaManager(noArenas, lockManagerShrinkTimer);
+ jobArenaMgr = new JobArenaManager(noArenas, lockManagerShrinkTimer);
jobIdSlotMap = new ConcurrentHashMap<>();
dsLockCache = new ThreadLocal<DatasetLockCache>() {
protected DatasetLockCache initialValue() {
@@ -733,15 +735,26 @@
private static class DatasetLockCache {
private long jobId = -1;
private HashMap<Integer,Byte> lockCache = new HashMap<Integer,Byte>();
+ // size 1 cache to avoid the boxing/unboxing that comes with the
+ // access to the HashMap
+ private int cDsId = -1;
+ private byte cDsLockMode = -1;
public boolean contains(final int jobId, final int dsId, byte dsLockMode) {
if (this.jobId == jobId) {
+ if (this.cDsId == dsId && this.cDsLockMode == dsLockMode) {
+ return true;
+ }
final Byte cachedLockMode = this.lockCache.get(dsId);
if (cachedLockMode != null && cachedLockMode == dsLockMode) {
+ this.cDsId = dsId;
+ this.cDsLockMode = dsLockMode;
return true;
}
} else {
this.jobId = -1;
+ this.cDsId = -1;
+ this.cDsLockMode = -1;
this.lockCache.clear();
}
return false;
@@ -749,6 +762,8 @@
public void put(final int jobId, final int dsId, byte dsLockMode) {
this.jobId = jobId;
+ this.cDsId = dsId;
+ this.cDsLockMode = dsLockMode;
this.lockCache.put(dsId, dsLockMode);
}
diff --git a/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/RecordManagerTypes.java b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/RecordManagerTypes.java
index b467cc3..27f2981 100644
--- a/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/RecordManagerTypes.java
+++ b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/RecordManagerTypes.java
@@ -22,6 +22,14 @@
public static class Global {
+ public static long build(int arenaId, int allocId, int localId) {
+ long result = arenaId;
+ result = result << 48;
+ result |= (allocId << 32);
+ result |= localId;
+ return result;
+ }
+
public static int arenaId(long l) {
return (int)((l >>> 48) & 0xffff);
}