提交 76011ce9 authored 作者: Thomas Mueller's avatar Thomas Mueller

Page store: make caches re-entrant

上级 0a9d56c0
...@@ -126,11 +126,13 @@ public class CacheLRU implements Cache { ...@@ -126,11 +126,13 @@ public class CacheLRU implements Cache {
private void removeOld() throws SQLException { private void removeOld() throws SQLException {
int i = 0; int i = 0;
int todoImplementInOtherCachesAsWell;
ObjectArray<CacheObject> changed = ObjectArray.newInstance(); ObjectArray<CacheObject> changed = ObjectArray.newInstance();
int mem = sizeMemory; int mem = sizeMemory;
int rc = recordCount; int rc = recordCount;
CacheObject next = head.next;
while (mem * 4 > maxSize * 3 && rc > Constants.CACHE_MIN_RECORDS) { while (mem * 4 > maxSize * 3 && rc > Constants.CACHE_MIN_RECORDS) {
CacheObject check = next;
next = check.next;
i++; i++;
if (i == recordCount) { if (i == recordCount) {
writer.flushLog(); writer.flushLog();
...@@ -142,35 +144,47 @@ public class CacheLRU implements Cache { ...@@ -142,35 +144,47 @@ public class CacheLRU implements Cache {
writer.getTrace().info("Cannot remove records, cache size too small?"); writer.getTrace().info("Cannot remove records, cache size too small?");
break; break;
} }
CacheObject last = head.next; if (SysProperties.CHECK && check == head) {
if (SysProperties.CHECK && last == head) {
Message.throwInternalError("try to remove head"); Message.throwInternalError("try to remove head");
} }
// we are not allowed to remove it if the log is not yet written // we are not allowed to remove it if the log is not yet written
// (because we need to log before writing the data) // (because we need to log before writing the data)
// also, can't write it if the record is pinned // also, can't write it if the record is pinned
if (!last.canRemove()) { if (!check.canRemove()) {
removeFromLinkedList(last); removeFromLinkedList(check);
addToFront(last); addToFront(check);
continue; continue;
} }
if (last.isChanged()) { rc--;
changed.add(last); mem -= check.getMemorySize();
if (check.isChanged()) {
changed.add(check);
} else { } else {
remove(last.getPos()); remove(check.getPos());
} }
rc--;
mem -= last.getMemorySize();
} }
if (changed.size() > 0) { if (changed.size() > 0) {
CacheObject.sort(changed); CacheObject.sort(changed);
for (i = 0; i < changed.size(); i++) { int max = maxSize;
CacheObject rec = changed.get(i); try {
writer.writeBack(rec); // temporary disable size checking,
// to avoid stack overflow
maxSize = Integer.MAX_VALUE;
for (i = 0; i < changed.size(); i++) {
CacheObject rec = changed.get(i);
writer.writeBack(rec);
}
} finally {
maxSize = max;
} }
for (i = 0; i < changed.size(); i++) { for (i = 0; i < changed.size(); i++) {
CacheObject rec = changed.get(i); CacheObject rec = changed.get(i);
remove(rec.getPos()); remove(rec.getPos());
if (SysProperties.CHECK) {
if (rec.next != null) {
throw Message.throwInternalError();
}
}
} }
} }
} }
......
...@@ -62,8 +62,8 @@ class CacheTQ implements Cache { ...@@ -62,8 +62,8 @@ class CacheTQ implements Cache {
private void recalculateMax() { private void recalculateMax() {
maxMain = maxSize; maxMain = maxSize;
maxIn = maxSize * PERCENT_IN / 100; maxIn = Math.max(1, maxSize * PERCENT_IN / 100);
maxOut = maxSize * PERCENT_OUT / 100; maxOut = Math.max(1, maxSize * PERCENT_OUT / 100);
} }
private void addToFront(CacheObject head, CacheObject rec) { private void addToFront(CacheObject head, CacheObject rec) {
...@@ -140,7 +140,9 @@ class CacheTQ implements Cache { ...@@ -140,7 +140,9 @@ class CacheTQ implements Cache {
} while (rec.getPos() != pos); } while (rec.getPos() != pos);
last.chained = rec.chained; last.chained = rec.chained;
} }
recordCount--; if (!(rec instanceof CacheHead)) {
recordCount--;
}
if (SysProperties.CHECK) { if (SysProperties.CHECK) {
rec.chained = null; rec.chained = null;
} }
...@@ -161,7 +163,7 @@ class CacheTQ implements Cache { ...@@ -161,7 +163,7 @@ class CacheTQ implements Cache {
private void removeOldIfRequired() throws SQLException { private void removeOldIfRequired() throws SQLException {
// a small method, to allow inlining // a small method, to allow inlining
if ((sizeIn >= maxIn) || (sizeOut >= maxOut) || (sizeMain >= maxMain)) { if ((sizeIn >= maxIn) || (sizeMain >= maxMain)) {
removeOld(); removeOld();
} }
} }
...@@ -169,66 +171,101 @@ class CacheTQ implements Cache { ...@@ -169,66 +171,101 @@ class CacheTQ implements Cache {
private void removeOld() throws SQLException { private void removeOld() throws SQLException {
int i = 0; int i = 0;
ObjectArray<CacheObject> changed = ObjectArray.newInstance(); ObjectArray<CacheObject> changed = ObjectArray.newInstance();
while (((sizeIn * 4 > maxIn * 3) || (sizeOut * 4 > maxOut * 3) || (sizeMain * 4 > maxMain * 3)) int si = sizeIn, sm = sizeMain, rc = recordCount;
&& recordCount > Constants.CACHE_MIN_RECORDS) { CacheObject inNext = headIn.next, mainNext = headMain.next;
while (((si * 4 > maxIn * 3) || (sm * 4 > maxMain * 3))
&& rc > Constants.CACHE_MIN_RECORDS) {
i++; i++;
if (i == recordCount) { if (i == rc) {
writer.flushLog(); writer.flushLog();
} }
if (i >= recordCount * 2) { if (i >= rc * 2) {
// can't remove any record, because the log is not written yet // can't remove any record, because the log is not written yet
// hopefully this does not happen too much, but it could happen // hopefully this does not happen too much, but it could happen
// theoretically // theoretically
writer.getTrace().info("Cannot remove records, cache size too small?"); writer.getTrace().info("Cannot remove records, cache size too small?");
break; break;
} }
if (sizeIn > maxIn) { if (si > maxIn) {
CacheObject r = headIn.next; CacheObject r = inNext;
inNext = r.next;
if (!r.canRemove()) { if (!r.canRemove()) {
removeFromList(r); removeFromList(r);
addToFront(headIn, r); addToFront(headIn, r);
continue; continue;
} }
sizeIn -= r.getMemorySize(); rc--;
int pos = r.getPos(); si -= r.getMemorySize();
removeCacheObject(pos);
removeFromList(r);
if (r.isChanged()) { if (r.isChanged()) {
changed.add(r); changed.add(r);
} else {
remove(r);
} }
r = new CacheHead(); } else if (sm > 0) {
r.setPos(pos); CacheObject r = mainNext;
r.cacheQueue = OUT; mainNext = r.next;
putCacheObject(r);
addToFront(headOut, r);
sizeOut++;
if (sizeOut >= maxOut) {
r = headOut.next;
sizeOut--;
removeCacheObject(r.getPos());
removeFromList(r);
}
} else if (sizeMain > 0) {
CacheObject r = headMain.next;
if (!r.canRemove() && !(r instanceof CacheHead)) { if (!r.canRemove() && !(r instanceof CacheHead)) {
removeFromList(r); removeFromList(r);
addToFront(headMain, r); addToFront(headMain, r);
continue; continue;
} }
sizeMain -= r.getMemorySize(); rc--;
removeCacheObject(r.getPos()); sm -= r.getMemorySize();
removeFromList(r);
if (r.isChanged()) { if (r.isChanged()) {
changed.add(r); changed.add(r);
} else {
remove(r);
} }
} }
} }
if (changed.size() > 0) { if (changed.size() > 0) {
CacheObject.sort(changed); int mm = maxMain;
int mi = maxIn;
try {
// temporary disable size checking,
// to avoid stack overflow
maxMain = Integer.MAX_VALUE;
maxIn = Integer.MAX_VALUE;
CacheObject.sort(changed);
for (i = 0; i < changed.size(); i++) {
CacheObject rec = changed.get(i);
writer.writeBack(rec);
}
} finally {
maxMain = mm;
maxIn = mi;
}
for (i = 0; i < changed.size(); i++) { for (i = 0; i < changed.size(); i++) {
CacheObject rec = changed.get(i); CacheObject rec = changed.get(i);
writer.writeBack(rec); remove(rec);
}
}
}
private void remove(CacheObject r) {
int pos = r.getPos();
removeCacheObject(pos);
removeFromList(r);
if (r.cacheQueue == IN) {
// remove the record from the IN queue
sizeIn -= r.getMemorySize();
// replace it with an OUT record
r = new CacheHead();
r.setPos(pos);
r.cacheQueue = OUT;
putCacheObject(r);
addToFront(headOut, r);
sizeOut++;
while (sizeOut >= maxOut) {
r = headOut.next;
sizeOut--;
removeCacheObject(r.getPos());
removeFromList(r);
} }
} else if (r.cacheQueue == MAIN) {
sizeMain -= r.getMemorySize();
} else {
throw Message.throwInternalError();
} }
} }
...@@ -268,10 +305,21 @@ class CacheTQ implements Cache { ...@@ -268,10 +305,21 @@ class CacheTQ implements Cache {
int index = rec.getPos() & mask; int index = rec.getPos() & mask;
rec.chained = values[index]; rec.chained = values[index];
values[index] = rec; values[index] = rec;
recordCount++; if (!(rec instanceof CacheHead)) {
recordCount++;
}
} }
public void put(CacheObject rec) throws SQLException { public void put(CacheObject rec) throws SQLException {
if (SysProperties.CHECK) {
int pos = rec.getPos();
for (int i = 0; i < rec.getBlockCount(); i++) {
CacheObject old = find(pos + i);
if (old != null) {
Message.throwInternalError("try to add a record twice pos:" + pos + " i:" + i);
}
}
}
int pos = rec.getPos(); int pos = rec.getPos();
CacheObject r = findCacheObject(pos); CacheObject r = findCacheObject(pos);
if (r != null) { if (r != null) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论