Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Allows for less contention around PersistenceWindowPool#refreshBricks…

…() by

monitoring if there's a thread currently doing refresh or not. If the
current thread is about to refresh and there's another one already
refreshing then instead of waiting for the refresh to complete, just skip
refreshing in the current thread.
  • Loading branch information...
commit 16546fe1294b9b96b0c3a855ccdfcf24c9351705 1 parent 0beff1c
@tinwelint tinwelint authored apcj committed
View
111 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/store/PersistenceWindowPool.java
@@ -28,6 +28,9 @@
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -70,6 +73,11 @@
private final boolean readOnly;
+ private final AtomicBoolean refreshing = new AtomicBoolean();
+ private final AtomicInteger avertedRefreshes = new AtomicInteger();
+ private final AtomicLong refreshTime = new AtomicLong();
+ private final AtomicInteger refreshes = new AtomicInteger();
+
/**
* Create new pool for a store.
*
@@ -465,50 +473,72 @@ private void refreshBricks()
if ( brickMiss < REFRESH_BRICK_COUNT || brickSize <= 0 )
return;
- synchronized ( this )
+ if ( refreshing.compareAndSet( false, true ) )
{
- brickMiss = 0;
- Pair<List<BrickElement>, List<BrickElement>> currentMappings = gatherMappedVersusUnmappedWindows();
- List<BrickElement> mappedBricks = currentMappings.first();
- List<BrickElement> unmappedBricks = currentMappings.other();
-
- // Fill up unused memory, i.e. map unmapped bricks as much as available memory allows
- // and request patterns signals. Start the loop from the end of the array where the
- // bricks with highest hit ratio are.
- int unmappedIndex = unmappedBricks.size() - 1;
- while ( memUsed + brickSize <= availableMem && unmappedIndex >= 0 )
+ // No one is doing refresh right now, go ahead and do it
+ try
{
- BrickElement unmappedBrick = unmappedBricks.get( unmappedIndex-- );
- if ( unmappedBrick.getHit() == 0 )
- // We have more memory available, but no more windows have actually
- // been requested so don't map unused random windows.
- return;
-
- allocateNewWindow( unmappedBrick );
+ long t = System.currentTimeMillis();
+ doRefreshBricks();
+ refreshes.incrementAndGet();
+ refreshTime.addAndGet( System.currentTimeMillis()-t );
}
+ finally
+ {
+ refreshing.set( false );
+ }
+ }
+ else
+ {
+ // Another thread is doing refresh right now, trust it to refresh the bricks
+ // and just go about my business.
+ avertedRefreshes.incrementAndGet();
+ }
+ }
+
+ private synchronized void doRefreshBricks()
+ {
+ brickMiss = 0;
+ Pair<List<BrickElement>, List<BrickElement>> currentMappings = gatherMappedVersusUnmappedWindows();
+ List<BrickElement> mappedBricks = currentMappings.first();
+ List<BrickElement> unmappedBricks = currentMappings.other();
+
+ // Fill up unused memory, i.e. map unmapped bricks as much as available memory allows
+ // and request patterns signals. Start the loop from the end of the array where the
+ // bricks with highest hit ratio are.
+ int unmappedIndex = unmappedBricks.size() - 1;
+ while ( memUsed + brickSize <= availableMem && unmappedIndex >= 0 )
+ {
+ BrickElement unmappedBrick = unmappedBricks.get( unmappedIndex-- );
+ if ( unmappedBrick.getHit() == 0 )
+ // We have more memory available, but no more windows have actually
+ // been requested so don't map unused random windows.
+ return;
- // Switch bad/unused mappings. Start iterating over mapped bricks
- // from the beginning (those with lowest hit ratio) and unmapped from the end
- // (or rather where the fill-up-unused-memory loop above left off) where we've
- // got the unmapped bricks with highest hit ratio.
- int mappedIndex = 0;
- while ( unmappedIndex >= 0 && mappedIndex < mappedBricks.size() )
+ allocateNewWindow( unmappedBrick );
+ }
+
+ // Switch bad/unused mappings. Start iterating over mapped bricks
+ // from the beginning (those with lowest hit ratio) and unmapped from the end
+ // (or rather where the fill-up-unused-memory loop above left off) where we've
+ // got the unmapped bricks with highest hit ratio.
+ int mappedIndex = 0;
+ while ( unmappedIndex >= 0 && mappedIndex < mappedBricks.size() )
+ {
+ BrickElement mappedBrick = mappedBricks.get( mappedIndex++ );
+ BrickElement unmappedBrick = unmappedBricks.get( unmappedIndex-- );
+ if ( mappedBrick.getHit() >= unmappedBrick.getHit() )
+ // We've passed a point where we don't have any unmapped brick
+ // with a higher hit ratio then the lowest mapped brick. We're done.
+ break;
+
+ LockableWindow window = mappedBrick.getWindow();
+ if (window.writeOutAndCloseIfFree( readOnly ) )
{
- BrickElement mappedBrick = mappedBricks.get( mappedIndex++ );
- BrickElement unmappedBrick = unmappedBricks.get( unmappedIndex-- );
- if ( mappedBrick.getHit() >= unmappedBrick.getHit() )
- // We've passed a point where we don't have any unmapped brick
- // with a higher hit ratio then the lowest mapped brick. We're done.
- break;
-
- LockableWindow window = mappedBrick.getWindow();
- if (window.writeOutAndCloseIfFree( readOnly ) )
- {
- mappedBrick.setWindow( null );
- memUsed -= brickSize;
- if ( allocateNewWindow( unmappedBrick ) )
- switches++;
- }
+ mappedBrick.setWindow( null );
+ memUsed -= brickSize;
+ if ( allocateNewWindow( unmappedBrick ) )
+ switches++;
}
}
}
@@ -644,8 +674,9 @@ private void logWarn( String logMessage, Throwable cause )
WindowPoolStats getStats()
{
+ int avgRefreshTime = refreshes.get() == 0 ? 0 : (int)(refreshTime.get()/refreshes.get());
return new WindowPoolStats( storeName, availableMem, memUsed, brickCount,
- brickSize, hit, miss, ooe );
+ brickSize, hit, miss, ooe, switches, avgRefreshTime, refreshes.get(), avertedRefreshes.get() );
}
private static class BrickElement
View
42 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/store/WindowPoolStats.java
@@ -32,9 +32,18 @@
private final int hitCount;
private final int missCount;
private final int oomCount;
+
+ private int switches;
+
+ private int avgRefreshTime;
+
+ private int numRefreshes;
+
+ private int avertedRefreshes;
public WindowPoolStats( String name, long memAvail, long memUsed, int windowCount,
- int windowSize, int hitCount, int missCount, int oomCount )
+ int windowSize, int hitCount, int missCount, int oomCount, int switches, int avgRefreshTime,
+ int numRefreshes, int avertedRefreshes )
{
this.name = name;
this.memAvail = memAvail;
@@ -44,6 +53,10 @@ public WindowPoolStats( String name, long memAvail, long memUsed, int windowCoun
this.hitCount = hitCount;
this.missCount = missCount;
this.oomCount = oomCount;
+ this.switches = switches;
+ this.avgRefreshTime = avgRefreshTime;
+ this.numRefreshes = numRefreshes;
+ this.avertedRefreshes = avertedRefreshes;
}
public String getName()
@@ -86,6 +99,26 @@ public int getOomCount()
return oomCount;
}
+ public int getSwitches()
+ {
+ return switches;
+ }
+
+ public int getAvgRefreshTime()
+ {
+ return avgRefreshTime;
+ }
+
+ public int getNumRefreshes()
+ {
+ return numRefreshes;
+ }
+
+ public int getAvertedRefreshes()
+ {
+ return avertedRefreshes;
+ }
+
@Override
public String toString()
{
@@ -96,6 +129,11 @@ public String toString()
"win size:" + windowSize + " " +
"hits:" + hitCount + " " +
"misses:" + missCount + " " +
- "ooms:" + oomCount + "]";
+ "ooms:" + oomCount + " " +
+ "switches:" + switches + " " +
+ "avg refr time:" + avgRefreshTime + " " +
+ "refreshes:" + numRefreshes + " " +
+ "averted refreshes:" + avertedRefreshes +
+ "]";
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.