提交 f8d4e81f authored 作者: Noel Grandin's avatar Noel Grandin

fix concurrenccy in freedPageSpace

just seen a ConcurrentModificationException on Jenkins.

It looks like we can access the Map<Integer, Chunk> from different threads concurrently without taking the same locks. So make it a ConcurrentHashMap. Nothing useful we can lock on here without introducing an ABBA deadlock.
上级 b8bbe7c1
...@@ -184,10 +184,14 @@ public final class MVStore { ...@@ -184,10 +184,14 @@ public final class MVStore {
/** /**
* The map of temporarily freed storage space caused by freed pages. The key * The map of temporarily freed storage space caused by freed pages. The key
* is the unsaved version, the value is the map of chunks. The maps contains * is the unsaved version, the value is the map of chunks. The maps contains
* the number of freed entries per chunk. Access is synchronized. * the number of freed entries per chunk.
* <p>
* Access is partially synchronized, hence the need for concurrent maps.
* Sometimes we hold the MVStore lock, sometimes the MVMap lock, and sometimes
* we even sync on the ConcurrentHashMap<Integer, Chunk> object.
*/ */
private final ConcurrentHashMap<Long, private final ConcurrentHashMap<Long,
HashMap<Integer, Chunk>> freedPageSpace = ConcurrentHashMap<Integer, Chunk>> freedPageSpace =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
/** /**
...@@ -1462,15 +1466,15 @@ public final class MVStore { ...@@ -1462,15 +1466,15 @@ public final class MVStore {
private void applyFreedSpace(long storeVersion) { private void applyFreedSpace(long storeVersion) {
while (true) { while (true) {
ArrayList<Chunk> modified = New.arrayList(); ArrayList<Chunk> modified = New.arrayList();
Iterator<Entry<Long, HashMap<Integer, Chunk>>> it; Iterator<Entry<Long, ConcurrentHashMap<Integer, Chunk>>> it;
it = freedPageSpace.entrySet().iterator(); it = freedPageSpace.entrySet().iterator();
while (it.hasNext()) { while (it.hasNext()) {
Entry<Long, HashMap<Integer, Chunk>> e = it.next(); Entry<Long, ConcurrentHashMap<Integer, Chunk>> e = it.next();
long v = e.getKey(); long v = e.getKey();
if (v > storeVersion) { if (v > storeVersion) {
continue; continue;
} }
HashMap<Integer, Chunk> freed = e.getValue(); ConcurrentHashMap<Integer, Chunk> freed = e.getValue();
for (Chunk f : freed.values()) { for (Chunk f : freed.values()) {
Chunk c = chunks.get(f.id); Chunk c = chunks.get(f.id);
if (c == null) { if (c == null) {
...@@ -1993,10 +1997,10 @@ public final class MVStore { ...@@ -1993,10 +1997,10 @@ public final class MVStore {
private void registerFreePage(long version, int chunkId, private void registerFreePage(long version, int chunkId,
long maxLengthLive, int pageCount) { long maxLengthLive, int pageCount) {
HashMap<Integer, Chunk> freed = freedPageSpace.get(version); ConcurrentHashMap<Integer, Chunk> freed = freedPageSpace.get(version);
if (freed == null) { if (freed == null) {
freed = New.hashMap(); freed = new ConcurrentHashMap<>();
HashMap<Integer, Chunk> f2 = freedPageSpace.putIfAbsent(version, ConcurrentHashMap<Integer, Chunk> f2 = freedPageSpace.putIfAbsent(version,
freed); freed);
if (f2 != null) { if (f2 != null) {
freed = f2; freed = f2;
...@@ -2006,8 +2010,7 @@ public final class MVStore { ...@@ -2006,8 +2010,7 @@ public final class MVStore {
synchronized (freed) { synchronized (freed) {
Chunk f = freed.get(chunkId); Chunk f = freed.get(chunkId);
if (f == null) { if (f == null) {
f = new Chunk(chunkId); f = freed.putIfAbsent(chunkId, new Chunk(chunkId));
freed.put(chunkId, f);
} }
f.maxLenLive -= maxLengthLive; f.maxLenLive -= maxLengthLive;
f.pageCountLive -= pageCount; f.pageCountLive -= pageCount;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论