-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
MuninnReadPageCursor.java
157 lines (140 loc) · 4.89 KB
/
MuninnReadPageCursor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*
* Copyright (c) 2002-2015 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.io.pagecache.impl.muninn;
import java.io.IOException;
import org.neo4j.io.pagecache.PageSwapper;
final class MuninnReadPageCursor extends MuninnPageCursor
{
private boolean optimisticLock;
@Override
protected void unpinCurrentPage()
{
MuninnPage p = page;
page = null;
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;
}
@Override
public boolean next() throws IOException
{
long lastPageId = assertPagedFileStillMappedAndGetIdOfLastPage();
if ( nextPageId > lastPageId )
{
return false;
}
unpinCurrentPage();
pin( nextPageId, false );
currentPageId = nextPageId;
nextPageId++;
return true;
}
@Override
protected void lockPage( MuninnPage page )
{
lockStamp = page.tryOptimisticRead();
optimisticLock = true;
}
@Override
protected void unlockPage( MuninnPage page )
{
}
@Override
protected void pinCursorToPage( MuninnPage page, long filePageId, PageSwapper swapper )
{
reset( page );
page.incrementUsage();
}
@Override
protected void convertPageFaultLock( MuninnPage page, long stamp )
{
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
}
@Override
public boolean shouldRetry() throws IOException
{
boolean needsRetry = optimisticLock && !page.validate( 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
// 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.
// 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
// fault itself is over.
page.unlockRead( lockStamp );
// 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;
pin( currentPageId, false );
}
}
return needsRetry;
}
@Override
public void putByte( byte value )
{
throw new IllegalStateException( "Cannot write to read-locked page" );
}
@Override
public void putLong( long value )
{
throw new IllegalStateException( "Cannot write to read-locked page" );
}
@Override
public void putInt( int value )
{
throw new IllegalStateException( "Cannot write to read-locked page" );
}
@Override
public void putBytes( byte[] data, int arrayOffset, int length )
{
throw new IllegalStateException( "Cannot write to read-locked page" );
}
@Override
public void putShort( short value )
{
throw new IllegalStateException( "Cannot write to read-locked page" );
}
}