-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
PageCursor.java
337 lines (303 loc) · 11.8 KB
/
PageCursor.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/*
* 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;
import java.io.File;
import java.io.IOException;
/**
* A PageCursor is returned from {@link org.neo4j.io.pagecache.PagedFile#io(long, int)},
* and is used to scan through pages and process them in a consistent and safe fashion.
* <p>
* A page must be processed in the following manner:
* <pre><code>
* try ( PageCursor cursor = pagedFile.io( pageId, pf_flags ) )
* {
* // Use 'if' for processing a single page,
* // use 'while' for scanning through pages:
* if ( cursor.next() )
* {
* do
* {
* processPage( cursor );
* } while ( cursor.shouldRetry() );
* // Any finalising, non-repeatable post-processing
* // goes here.
* }
* }
* catch ( IOException e )
* {
* // handle the error, somehow
* }
* </code></pre>
* <p>There are a couple of things to this pattern that are worth noting:
* <ul>
* <li>We use a try-with-resources clause to make sure that the resources
* associated with the PageCursor are always released properly.
* </li>
* <li>We use an if-clause for the next() call if we are only processing
* a single page, to make sure that the page exist and is accessible to us.
* </li>
* <li>We use a while-clause for next() if we are scanning through pages.
* </li>
* <li>We do our processing of the page in a do-while-retry loop, to
* make sure that we processed a page that was in a consistent state.
* </li>
* </ul>
* You can alternatively use the {@link #next(long)} method, to navigate the
* pages you need in a non-linear fashion.
*/
public interface PageCursor extends AutoCloseable
{
long UNBOUND_PAGE_ID = -1;
int UNBOUND_PAGE_SIZE = -1;
/**
* Get the signed byte at the current page offset, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
byte getByte();
/**
* Get the signed byte at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
byte getByte( int offset );
/**
* Set the signed byte at the current offset into the page, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
void putByte( byte value );
/**
* Set the signed byte at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
void putByte( int offset, byte value );
/**
* Get the signed long at the current page offset, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
long getLong();
/**
* Get the signed long at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
long getLong( int offset );
/**
* Set the signed long at the current offset into the page, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
void putLong( long value );
/**
* Set the signed long at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
void putLong( int offset, long value );
/**
* Get the signed int at the current page offset, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
int getInt();
/**
* Get the signed int at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
int getInt( int offset );
/**
* Set the signed int at the current offset into the page, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
void putInt( int value );
/**
* Set the signed int at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
void putInt( int offset, int value );
/**
* Get the unsigned int at the current page offset, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
long getUnsignedInt();
/**
* Get the unsigned int at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
long getUnsignedInt( int offset );
/**
* Fill the given array with bytes from the page, beginning at the current offset into the page,
* and then increment the current offset by the length of the array.
*
* @throws IndexOutOfBoundsException
* if the current offset plus the length of the array reaches beyond the end of the page.
*/
void getBytes( byte[] data );
/**
* Read the given length of bytes from the page into the given array, starting from the current offset into the
* page, and writing from the given array offset, and then increment the current offset by the length argument.
*
* @throws IndexOutOfBoundsException
* if the current offset plus the length reaches beyond the end of the page.
*/
void getBytes( byte[] data, int arrayOffset, int length );
/**
* Write out all the bytes of the given array into the page, beginning at the current offset into the page,
* and then increment the current offset by the length of the array.
*
* @throws IndexOutOfBoundsException
* if the current offset plus the length of the array reaches beyond the end of the page.
*/
void putBytes( byte[] data );
/**
* Write out the given length of bytes from the given offset into the the given array of bytes, into the page,
* beginning at the current offset into the page, and then increment the current offset by the length argument.
*
* @throws IndexOutOfBoundsException
* if the current offset plus the length reaches beyond the end of the page.
*/
void putBytes( byte[] data, int arrayOffset, int length );
/**
* Get the signed short at the current page offset, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
short getShort();
/**
* Get the signed short at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
short getShort( int offset );
/**
* Set the signed short at the current offset into the page, and then increment the offset by one.
*
* @throws IndexOutOfBoundsException
* if the current offset is not within the page bounds.
*/
void putShort( short value );
/**
* Set the signed short at the given offset into the page.
* Leaves the current page offset unchanged.
*
* @throws IndexOutOfBoundsException
* if the given offset is not within the page bounds.
*/
void putShort( int offset, short value );
/**
* Set the current offset into the page, for interacting with the page through the read and write methods that do
* not take a specific offset as an argument.
*/
void setOffset( int offset );
/**
* Get the current offset into the page, which is the location on the page where the next interaction would take
* place through the read and write methods that do not take a specific offset as an argument.
*/
int getOffset();
/**
* Get the file page id that the cursor is currently positioned at, or
* UNBOUND_PAGE_ID if next() has not yet been called on this cursor, or returned false.
* A call to rewind() will make the current page id unbound as well, until
* next() is called.
*/
long getCurrentPageId();
/**
* Get the file page size of the page that the cursor is currently positioned at,
* or UNBOUND_PAGE_SIZE if next() has not yet been called on this cursor, or returned false.
* A call to rewind() will make the current page unbound as well, until next() is called.
*/
int getCurrentPageSize();
/**
* Get the file the cursor is currently bound to, or {@code null} if next() has not yet been called on this
* cursor, or returned false.
* A call to rewind() will make the cursor unbound as well, until next() is called.
*/
File getCurrentFile();
/**
* Rewinds the cursor to its initial condition, as if freshly returned from
* an equivalent io() call. In other words, the next call to next() will
* move the cursor to the starting page that was specified in the io() that
* produced the cursor.
*/
void rewind();
/**
* Moves the cursor to the next page, if any, and returns true when it is
* ready to be processed. Returns false if there are no more pages to be
* processed. For instance, if the cursor was requested with PF_NO_GROW
* and the page most recently processed was the last page in the file.
*/
boolean next() throws IOException;
/**
* Moves the cursor to the page specified by the given pageId, if any,
* and returns true when it is ready to be processed. Returns false if
* for instance, the cursor was requested with PF_NO_GROW and the page
* most recently processed was the last page in the file.
*/
boolean next( long pageId ) throws IOException;
/**
* Relinquishes all resources associated with this cursor, including the
* cursor itself. The cursor cannot be used after this call.
* @see AutoCloseable#close()
*/
void close();
/**
* Returns true if the page has entered an inconsistent state since the
* last call to next() or shouldRetry().
* If this method returns true, the in-page offset of the cursor will be
* reset to zero.
*
* @throws IOException If the page was evicted while doing IO, the cursor will have
* to do a page fault to get the page back.
* This may throw an IOException.
*/
boolean shouldRetry() throws IOException;
}