Skip to content

Commit

Permalink
Allows for less contention around PersistenceWindowPool#refreshBricks…
Browse files Browse the repository at this point in the history
…() 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
tinwelint authored and apcj committed Aug 20, 2012
1 parent 0beff1c commit 16546fe
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 42 deletions.
Expand Up @@ -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;

Expand Down Expand Up @@ -70,6 +73,11 @@ public class PersistenceWindowPool

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.
*
Expand Down Expand Up @@ -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++;
}
}
}
Expand Down Expand Up @@ -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
Expand Down
Expand Up @@ -32,9 +32,18 @@ public class WindowPoolStats
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;
Expand All @@ -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()
Expand Down Expand Up @@ -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()
{
Expand All @@ -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 +
"]";
}
}

0 comments on commit 16546fe

Please sign in to comment.