diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/DaemonThreadFactory.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/DaemonThreadFactory.java index 79ea4b6674b77..18cdc926a3fd8 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/DaemonThreadFactory.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/DaemonThreadFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2015 "Neo Technology," + * Copyright (c) 2002-2016 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPage.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPage.java index 9e6361708190b..42d5ce00a711d 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPage.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPage.java @@ -21,7 +21,6 @@ import java.io.IOException; -import org.neo4j.concurrent.jsr166e.StampedLock; import org.neo4j.io.pagecache.Page; import org.neo4j.io.pagecache.PageCursor; import org.neo4j.io.pagecache.PageSwapper; @@ -34,7 +33,7 @@ import static java.lang.String.format; -final class MuninnPage extends StampedLock implements Page +final class MuninnPage extends OptiLock implements Page { private static final long usageStampOffset = UnsafeUtil.getFieldOffset( MuninnPage.class, "usageStamp" ); @@ -144,7 +143,6 @@ private void doFlush( long filePageId, FlushEventOpportunity flushOpportunity ) throws IOException { - assert isReadLocked() || isWriteLocked() : "doFlush requires lock"; FlushEvent event = flushOpportunity.beginFlush( filePageId, getCachePageId(), swapper ); try { @@ -168,7 +166,6 @@ public void fault( long filePageId, PageFaultEvent faultEvent ) throws IOException { - assert isWriteLocked(): "Cannot fault page without write-lock"; if ( this.swapper != null || this.filePageId != PageCursor.UNBOUND_PAGE_ID ) { String msg = format( @@ -198,7 +195,6 @@ public void fault( */ public void evict( EvictionEvent evictionEvent ) throws IOException { - assert isWriteLocked(): "Cannot evict page without write-lock"; long filePageId = this.filePageId; evictionEvent.setCachePageId( getCachePageId() ); evictionEvent.setFilePageId( filePageId ); @@ -232,7 +228,6 @@ public boolean isBoundTo( PageSwapper swapper, long filePageId ) */ public void initBuffer() { - assert isWriteLocked(): "Cannot initBuffer without write-lock"; if ( pointer == 0 ) { pointer = memoryManager.allocateAligned( size() ); @@ -249,6 +244,6 @@ public String toString() { return format( "MuninnPage@%x[%s -> %x, filePageId = %s%s, swapper = %s]%s", hashCode(), getCachePageId(), pointer, filePageId, (isDirty() ? ", dirty" : ""), - swapper, getLockStateString() ); + swapper, super.toString() ); } } diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCache.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCache.java index 9501d090d89d9..65f5203c15dbb 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCache.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCache.java @@ -663,8 +663,7 @@ private MuninnPage cooperativelyEvict( PageFaultEvent faultEvent ) throws IOExce if ( page.isLoaded() && page.decrementUsage() ) { - long stamp = page.tryWriteLock(); - if ( stamp != 0 ) + if ( page.tryExclusiveLock() ) { // We got the write lock. Time to evict the page! try ( EvictionEvent evictionEvent = faultEvent.beginEviction() ) @@ -673,7 +672,7 @@ private MuninnPage cooperativelyEvict( PageFaultEvent faultEvent ) throws IOExce } finally { - page.unlockWrite( stamp ); + page.unlockExclusive(); } } } @@ -790,8 +789,7 @@ int evictPages( int pageCountToEvict, int clockArm, EvictionRunEvent evictionRun if ( page.isLoaded() && page.decrementUsage() ) { - long stamp = page.tryWriteLock(); - if ( stamp != 0 ) + if ( page.tryExclusiveLock() ) { // We got the lock. // Assume that the eviction is going to succeed, so that we @@ -812,7 +810,7 @@ int evictPages( int pageCountToEvict, int clockArm, EvictionRunEvent evictionRun } finally { - page.unlockWrite( stamp ); + page.unlockExclusive(); } if ( pageEvicted ) @@ -951,14 +949,13 @@ private long flushAtIORatio( double ratio ) // Skip the page if it is already write locked, or not dirty, or too popular. boolean thisPageIsDirty = false; - if ( page.isWriteLocked() || !(thisPageIsDirty = page.isDirty()) || !page.decrementUsage() ) + if ( !(thisPageIsDirty = page.isDirty()) || !page.decrementUsage() ) { seenDirtyPages |= thisPageIsDirty; continue; // Continue looping to the next page. } - long stamp = page.tryReadLock(); - if ( stamp != 0 ) + if ( page.tryExclusiveLock() ) // TODO somehow avoid taking these exclusive locks, that we currently need to avoid racing with other flushes { try { @@ -984,7 +981,7 @@ private long flushAtIORatio( double ratio ) } finally { - page.unlockRead( stamp ); + page.unlockExclusive(); } } diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCursor.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCursor.java index 04a1a76e0cf2c..87313efde8b18 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCursor.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPageCursor.java @@ -47,7 +47,6 @@ abstract class MuninnPageCursor implements PageCursor protected int pf_flags; protected long currentPageId; protected long nextPageId; - protected long lockStamp; private long pointer; private int size; @@ -115,7 +114,6 @@ public final void close() protected void clearPageState() { size = 0; // make all future bound checks fail - lockStamp = 0; // make sure not to accidentally keep a lock state around page = null; // make all future page navigation fail } @@ -236,7 +234,6 @@ private MuninnPage pageFault( // we must make sure to release that write lock as well. PageFaultEvent faultEvent = pinEvent.beginPageFault(); MuninnPage page; - long stamp; try { // The grabFreePage method might throw. @@ -247,7 +244,10 @@ private MuninnPage pageFault( // their translation tables might race with eviction) and try to pin it. // However, they will all fail because when they try to pin, the page will either be 1) free, 2) bound to // our file, or 3) the page is write locked. - stamp = page.writeLock(); + if ( !page.tryExclusiveLock() ) + { + throw new AssertionError( "Unable to take exclusive lock on free page" ); + } } catch ( Throwable throwable ) { @@ -273,7 +273,7 @@ private MuninnPage pageFault( catch ( Throwable throwable ) { // Make sure to unlock the page, so the eviction thread can pick up our trash. - page.unlockWrite( stamp ); + page.unlockExclusive(); // Make sure to unstuck the page fault latch. UnsafeUtil.putObjectVolatile( chunk, chunkOffset, null ); latch.release(); @@ -281,7 +281,7 @@ private MuninnPage pageFault( pinEvent.done(); throw throwable; } - convertPageFaultLock( page, stamp ); + convertPageFaultLock( page ); UnsafeUtil.putObjectVolatile( chunk, chunkOffset, page ); latch.release(); faultEvent.done(); @@ -295,7 +295,7 @@ protected long assertPagedFileStillMappedAndGetIdOfLastPage() protected abstract void unpinCurrentPage(); - protected abstract void convertPageFaultLock( MuninnPage page, long stamp ); + protected abstract void convertPageFaultLock( MuninnPage page ); protected abstract void pinCursorToPage( MuninnPage page, long filePageId, PageSwapper swapper ); diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPagedFile.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPagedFile.java index 8db0409a0dd61..16b8fd2fa2e2d 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPagedFile.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnPagedFile.java @@ -193,7 +193,6 @@ public void flushAndForce() throws IOException void flushAndForceInternal( FlushEventOpportunity flushOpportunity ) throws IOException { pageCache.pauseBackgroundFlushTask(); - long[] stamps = new long[translationTableChunkSize]; MuninnPage[] pages = new MuninnPage[translationTableChunkSize]; long filePageId = -1; // Start at -1 because we increment at the *start* of the chunk-loop iteration. try @@ -210,7 +209,7 @@ void flushAndForceInternal( FlushEventOpportunity flushOpportunity ) throws IOEx if ( element instanceof MuninnPage ) { MuninnPage page = (MuninnPage) element; - stamps[pagesGrabbed] = page.readLock(); + page.writeLock(); if ( page.isBoundTo( swapper, filePageId ) && page.isDirty() ) { // The page is still bound to the expected file and file page id after we locked it, @@ -222,17 +221,17 @@ void flushAndForceInternal( FlushEventOpportunity flushOpportunity ) throws IOEx } else { - page.unlockRead( stamps[pagesGrabbed] ); + page.unlockWrite(); } } if ( pagesGrabbed > 0 ) { - pagesGrabbed = vectoredFlush( stamps, pages, pagesGrabbed, flushOpportunity ); + pagesGrabbed = vectoredFlush( pages, pagesGrabbed, flushOpportunity ); } } if ( pagesGrabbed > 0 ) { - vectoredFlush( stamps, pages, pagesGrabbed, flushOpportunity ); + vectoredFlush( pages, pagesGrabbed, flushOpportunity ); } } @@ -244,8 +243,7 @@ void flushAndForceInternal( FlushEventOpportunity flushOpportunity ) throws IOEx } } - private int vectoredFlush( - long[] stamps, MuninnPage[] pages, int pagesGrabbed, FlushEventOpportunity flushOpportunity ) + private int vectoredFlush( MuninnPage[] pages, int pagesGrabbed, FlushEventOpportunity flushOpportunity ) throws IOException { FlushEvent flush = null; @@ -284,7 +282,7 @@ private int vectoredFlush( // Always unlock all the pages in the vector for ( int j = 0; j < pagesGrabbed; j++ ) { - pages[j].unlockRead( stamps[j] ); + pages[j].unlockWrite(); } } } diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnReadPageCursor.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnReadPageCursor.java index c10a6be85cae5..45a0f45f861f8 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnReadPageCursor.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnReadPageCursor.java @@ -25,7 +25,7 @@ final class MuninnReadPageCursor extends MuninnPageCursor { - private boolean optimisticLock; + protected long lockStamp; @Override protected void unpinCurrentPage() @@ -35,14 +35,8 @@ protected void unpinCurrentPage() if ( p != null ) { pinEvent.done(); - assert optimisticLock || p.isReadLocked() : - "pinned page wasn't really locked; not even optimistically: " + p; - - if ( !optimisticLock ) - { - p.unlockRead( lockStamp ); - } } + lockStamp = 0; // make sure not to accidentally keep a lock state around clearPageState(); } @@ -64,8 +58,7 @@ public boolean next() throws IOException @Override protected void lockPage( MuninnPage page ) { - lockStamp = page.tryOptimisticRead(); - optimisticLock = true; + lockStamp = page.tryOptimisticReadLock(); } @Override @@ -81,43 +74,37 @@ protected void pinCursorToPage( MuninnPage page, long filePageId, PageSwapper sw } @Override - protected void convertPageFaultLock( MuninnPage page, long stamp ) + protected void convertPageFaultLock( MuninnPage page ) { - stamp = page.tryConvertToReadLock( stamp ); - assert stamp != 0: "Converting a write lock to a read lock should always succeed"; - lockStamp = stamp; - optimisticLock = false; // We're using a pessimistic read lock + lockStamp = page.unlockExclusive(); } @Override public boolean shouldRetry() throws IOException { - boolean needsRetry = optimisticLock && !page.validate( lockStamp ); + boolean needsRetry = !page.validateReadLock( lockStamp ); if ( needsRetry ) { setOffset( 0 ); - optimisticLock = false; - lockStamp = page.readLock(); - // We have a pessimistic read lock on the page now. This prevents - // writes to the page, and it prevents the page from being evicted. - // However, it might have been evicted while we held the optimistic + lockStamp = page.tryOptimisticReadLock(); + // The page might have been evicted while we held the optimistic // read lock, so we need to check with page.pin that this is still // the page we're actually interested in: if ( !page.isBoundTo( pagedFile.swapper, currentPageId ) ) { // This is no longer the page we're interested in, so we have - // to release our lock and redo the pinning. + // to redo the pinning. // This might in turn lead to a new optimistic lock on a // different page if someone else has taken the page fault for // us. If nobody has done that, we'll take the page fault - // ourselves, and in that case we'll end up with first a write - // lock during the faulting, and then a read lock once the + // ourselves, and in that case we'll end up with first an exclusive + // lock during the faulting, and then an optimistic read lock once the // fault itself is over. - page.unlockRead( lockStamp ); - // Forget about this page in case pin() throws and the cursor + // First, forget about this page in case pin() throws and the cursor // is closed; we don't want unpinCurrentPage() to try unlocking // this page. page = null; + // Then try pin again. pin( currentPageId, false ); } } diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnWritePageCursor.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnWritePageCursor.java index 1a7b767be27ee..3fb1a4d7bc412 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnWritePageCursor.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/MuninnWritePageCursor.java @@ -32,7 +32,6 @@ protected void unpinCurrentPage() if ( page != null ) { pinEvent.done(); - assert page.isWriteLocked(): "page pinned for writing was not write locked: " + page; unlockPage( page ); } clearPageState(); @@ -63,13 +62,13 @@ public boolean next() throws IOException @Override protected void lockPage( MuninnPage page ) { - lockStamp = page.writeLock(); + page.writeLock(); } @Override protected void unlockPage( MuninnPage page ) { - page.unlockWrite( lockStamp ); + page.unlockWrite(); } @Override @@ -87,9 +86,10 @@ protected void pinCursorToPage( MuninnPage page, long filePageId, PageSwapper sw } @Override - protected void convertPageFaultLock( MuninnPage page, long stamp ) + protected void convertPageFaultLock( MuninnPage page ) { - lockStamp = stamp; + page.unlockExclusive(); // TODO page.unlockExclusiveAndTakeWriteLock + page.writeLock(); } @Override diff --git a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/OptiLock.java b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/OptiLock.java index 0966b2aa9f29f..d45b78277b853 100644 --- a/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/OptiLock.java +++ b/community/io/src/main/java/org/neo4j/io/pagecache/impl/muninn/OptiLock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2015 "Neo Technology," + * Copyright (c) 2002-2016 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. @@ -222,6 +222,11 @@ public long unlockExclusive() return n; } + public void unlockExclusiveAndTakeWriteLock() + { + // TODO + } + private void throwUnmatchedUnlockExclusive( long s ) { throw new IllegalMonitorStateException( "Unmatched unlockExclusive: " + describeState( s ) ); diff --git a/community/io/src/test/java/org/neo4j/io/pagecache/impl/muninn/OptiLockStressTest.java b/community/io/src/test/java/org/neo4j/io/pagecache/impl/muninn/OptiLockStressTest.java index c2e1164bcbc83..7c6fa0d02cbb9 100644 --- a/community/io/src/test/java/org/neo4j/io/pagecache/impl/muninn/OptiLockStressTest.java +++ b/community/io/src/test/java/org/neo4j/io/pagecache/impl/muninn/OptiLockStressTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2015 "Neo Technology," + * Copyright (c) 2002-2016 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. diff --git a/community/io/src/test/java/org/neo4j/io/pagecache/impl/muninn/OptiLockTest.java b/community/io/src/test/java/org/neo4j/io/pagecache/impl/muninn/OptiLockTest.java index 0eaa3ca54aee5..e2d5f1b0c25f5 100644 --- a/community/io/src/test/java/org/neo4j/io/pagecache/impl/muninn/OptiLockTest.java +++ b/community/io/src/test/java/org/neo4j/io/pagecache/impl/muninn/OptiLockTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2015 "Neo Technology," + * Copyright (c) 2002-2016 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j.