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 package jdbm.recman;
49
50 import java.io.IOException;
51
52
53
54
55 final class PhysicalRowIdManager
56 {
57
58
59 private RecordFile file;
60 private PageManager pageman;
61 private FreePhysicalRowIdPageManager freeman;
62
63
64
65
66
67 PhysicalRowIdManager( RecordFile file, PageManager pageManager )
68 throws IOException
69 {
70 this.file = file;
71 this.pageman = pageManager;
72 this.freeman = new FreePhysicalRowIdPageManager(file, pageman);
73 }
74
75
76
77
78 Location insert( byte[] data, int start, int length )
79 throws IOException
80 {
81 Location retval = alloc( length );
82 write( retval, data, start, length );
83 return retval;
84 }
85
86
87
88
89
90 Location update( Location rowid, byte[] data, int start, int length )
91 throws IOException
92 {
93
94 BlockIo block = file.get( rowid.getBlock() );
95 RecordHeader head = new RecordHeader( block, rowid.getOffset() );
96 if ( length > head.getAvailableSize() ) {
97
98 file.release( block );
99 free( rowid );
100 rowid = alloc( length );
101 } else {
102 file.release( block );
103 }
104
105
106 write( rowid, data, start, length );
107 return rowid;
108 }
109
110
111
112
113 void delete( Location rowid )
114 throws IOException
115 {
116 free( rowid );
117 }
118
119
120
121
122 byte[] fetch( Location rowid )
123 throws IOException
124 {
125
126 PageCursor curs = new PageCursor( pageman, rowid.getBlock() );
127 BlockIo block = file.get( curs.getCurrent() );
128 RecordHeader head = new RecordHeader( block, rowid.getOffset() );
129
130
131 byte[] retval = new byte[ head.getCurrentSize() ];
132 if ( retval.length == 0 ) {
133 file.release( curs.getCurrent(), false );
134 return retval;
135 }
136
137
138 int offsetInBuffer = 0;
139 int leftToRead = retval.length;
140 short dataOffset = (short) (rowid.getOffset() + RecordHeader.SIZE);
141 while ( leftToRead > 0 ) {
142
143 int toCopy = RecordFile.BLOCK_SIZE - dataOffset;
144 if ( leftToRead < toCopy ) {
145 toCopy = leftToRead;
146 }
147 System.arraycopy( block.getData(), dataOffset,
148 retval, offsetInBuffer,
149 toCopy );
150
151
152 leftToRead -= toCopy;
153 offsetInBuffer += toCopy;
154
155 file.release( block );
156
157 if ( leftToRead > 0 ) {
158 block = file.get( curs.next() );
159 dataOffset = DataPage.O_DATA;
160 }
161
162 }
163
164 return retval;
165 }
166
167
168
169
170 private Location alloc( int size )
171 throws IOException
172 {
173 Location retval = freeman.get( size );
174 if ( retval == null ) {
175 retval = allocNew( size, pageman.getLast( Magic.USED_PAGE ) );
176 }
177 return retval;
178 }
179
180
181
182
183
184
185 private Location allocNew( int size, long start )
186 throws IOException
187 {
188 BlockIo curBlock;
189 DataPage curPage;
190 if ( start == 0 ) {
191
192 start = pageman.allocate( Magic.USED_PAGE );
193 curBlock = file.get( start );
194 curPage = DataPage.getDataPageView( curBlock );
195 curPage.setFirst( DataPage.O_DATA );
196 RecordHeader hdr = new RecordHeader( curBlock, DataPage.O_DATA );
197 hdr.setAvailableSize( 0 );
198 hdr.setCurrentSize( 0 );
199 } else {
200 curBlock = file.get( start );
201 curPage = DataPage.getDataPageView( curBlock );
202 }
203
204
205
206 short pos = curPage.getFirst();
207 if ( pos == 0 ) {
208
209 file.release( curBlock );
210 return allocNew( size, 0 );
211 }
212
213 RecordHeader hdr = new RecordHeader( curBlock, pos );
214 while ( hdr.getAvailableSize() != 0 && pos < RecordFile.BLOCK_SIZE ) {
215 pos += hdr.getAvailableSize() + RecordHeader.SIZE;
216 if ( pos == RecordFile.BLOCK_SIZE ) {
217
218 file.release( curBlock );
219 return allocNew( size, 0 );
220 }
221
222 hdr = new RecordHeader( curBlock, pos );
223 }
224
225 if ( pos == RecordHeader.SIZE ) {
226
227
228 file.release( curBlock );
229 }
230
231
232
233 Location retval = new Location( start, pos );
234 int freeHere = RecordFile.BLOCK_SIZE - pos - RecordHeader.SIZE;
235 if ( freeHere < size ) {
236
237
238
239 int lastSize = (size - freeHere) % DataPage.DATA_PER_PAGE;
240 if (( DataPage.DATA_PER_PAGE - lastSize ) < (RecordHeader.SIZE + 16) ) {
241 size += (DataPage.DATA_PER_PAGE - lastSize);
242 }
243
244
245 hdr.setAvailableSize( size );
246 file.release( start, true );
247
248 int neededLeft = size - freeHere;
249
250 while ( neededLeft >= DataPage.DATA_PER_PAGE ) {
251 start = pageman.allocate( Magic.USED_PAGE );
252 curBlock = file.get( start );
253 curPage = DataPage.getDataPageView( curBlock );
254 curPage.setFirst( (short) 0 );
255 file.release( start, true );
256 neededLeft -= DataPage.DATA_PER_PAGE;
257 }
258 if ( neededLeft > 0 ) {
259
260 start = pageman.allocate( Magic.USED_PAGE );
261 curBlock = file.get( start );
262 curPage = DataPage.getDataPageView( curBlock );
263 curPage.setFirst( (short) (DataPage.O_DATA + neededLeft) );
264 file.release( start, true );
265 }
266 } else {
267
268
269
270 if ( freeHere - size <= (16 + RecordHeader.SIZE) ) {
271 size = freeHere;
272 }
273 hdr.setAvailableSize( size );
274 file.release( start, true );
275 }
276 return retval;
277
278 }
279
280
281 private void free( Location id )
282 throws IOException
283 {
284
285 BlockIo curBlock = file.get( id.getBlock() );
286 DataPage curPage = DataPage.getDataPageView( curBlock );
287 RecordHeader hdr = new RecordHeader( curBlock, id.getOffset() );
288 hdr.setCurrentSize( 0 );
289 file.release( id.getBlock(), true );
290
291
292 freeman.put( id, hdr.getAvailableSize() );
293 }
294
295
296
297
298
299 private void write(Location rowid, byte[] data, int start, int length )
300 throws IOException
301 {
302 PageCursor curs = new PageCursor( pageman, rowid.getBlock() );
303 BlockIo block = file.get( curs.getCurrent() );
304 RecordHeader hdr = new RecordHeader( block, rowid.getOffset() );
305 hdr.setCurrentSize( length );
306 if ( length == 0 ) {
307 file.release( curs.getCurrent(), true );
308 return;
309 }
310
311
312 int offsetInBuffer = start;
313 int leftToWrite = length;
314 short dataOffset = (short) (rowid.getOffset() + RecordHeader.SIZE);
315 while ( leftToWrite > 0 ) {
316
317 int toCopy = RecordFile.BLOCK_SIZE - dataOffset;
318
319 if ( leftToWrite < toCopy ) {
320 toCopy = leftToWrite;
321 }
322 System.arraycopy( data, offsetInBuffer, block.getData(),
323 dataOffset, toCopy );
324
325
326 leftToWrite -= toCopy;
327 offsetInBuffer += toCopy;
328
329 file.release( curs.getCurrent(), true );
330
331 if ( leftToWrite > 0 ) {
332 block = file.get( curs.next() );
333 dataOffset = DataPage.O_DATA;
334 }
335 }
336 }
337 }
338