source: osm/applications/editors/josm/plugins/imagerycache/src/org/mapdb/StorageJournaled.java@ 29363

Last change on this file since 29363 was 29363, checked in by akks, 11 years ago

JOSM/ImageryCache: Initial commit

File size: 25.9 KB
Line 
1/*
2 * Copyright (c) 2012 Jan Kotek
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.mapdb;
18
19import java.io.IOError;
20import java.io.IOException;
21import java.nio.ByteBuffer;
22import java.util.ArrayList;
23
24/**
25 * StorageDirect which provides transaction and journal.
26 * Index file data are stored in memory+trans journal, phys file data are stored only in transaction journal.
27 *
28 * @author Jan Kotek
29 */
30public class StorageJournaled extends StorageDirect implements Engine {
31
32 protected static final long WRITE_INDEX_LONG = 1L <<48;
33 protected static final long WRITE_INDEX_LONG_ZERO = 2L <<48;
34 protected static final long WRITE_PHYS_LONG = 3L <<48;
35 protected static final long WRITE_PHYS_ARRAY = 4L <<48;
36
37 protected static final long WRITE_SKIP_BUFFER = 444L <<48;
38 /** last instruction in log file */
39 protected static final long WRITE_SEAL = 111L <<48;
40 /** added to offset 8 into log file, indicates that write was successful*/
41 protected static final long LOG_SEAL = 4566556446554645L;
42 public static final String TRANS_LOG_FILE_EXT = ".t";
43
44
45 protected Volume transLog;
46 protected final Volume.Factory volFac;
47 protected long transLogOffset;
48
49
50 protected long indexSize;
51 protected long physSize;
52 protected final LongMap<long[]> recordLogRefs = new LongHashMap<long[]>();
53 protected final LongMap<Long> recordIndexVals = new LongHashMap<Long>();
54 protected final LongMap<long[]> longStackPages = new LongHashMap<long[]>();
55 protected final LongMap<ArrayList<Long>> transLinkedPhysRecods = new LongHashMap<ArrayList<Long>>();
56
57
58 public StorageJournaled(Volume.Factory volFac){
59 this(volFac, false, false, false, false);
60 }
61
62 public StorageJournaled(Volume.Factory volFac, boolean appendOnly,
63 boolean deleteFilesOnExit, boolean failOnWrongHeader, boolean readOnly) {
64 super(volFac, appendOnly, deleteFilesOnExit, failOnWrongHeader, readOnly);
65 lock.writeLock().lock();
66 try{
67 this.volFac = volFac;
68 this.transLog = volFac.createTransLogVolume();
69 reloadIndexFile();
70 replayLogFile();
71 transLog = null;
72 }finally{
73 lock.writeLock().unlock();
74 }
75 }
76
77
78 protected void reloadIndexFile() {
79 transLogOffset = 0;
80 writeLock_checkLocked();
81 recordLogRefs.clear();
82 recordIndexVals.clear();
83 longStackPages.clear();
84 transLinkedPhysRecods.clear();
85 indexSize = index.getLong(RECID_CURRENT_INDEX_FILE_SIZE *8);
86 physSize = index.getLong(RECID_CURRENT_PHYS_FILE_SIZE*8);
87 writeLock_checkLocked();
88 }
89
90 protected void openLogIfNeeded(){
91 if(transLog!=null) return;
92 transLog = volFac.createTransLogVolume();
93 transLog.ensureAvailable(16);
94 transLog.putLong(0, HEADER);
95 transLog.putLong(8, 0L);
96 transLogOffset = 16;
97 }
98
99
100
101
102
103 @Override
104 public <A> long put(A value, Serializer<A> serializer) {
105 if(value==null||serializer==null) throw new NullPointerException();
106 try{
107 DataOutput2 out = new DataOutput2();
108 serializer.serialize(out,value);
109
110 try{
111 lock.writeLock().lock();
112 //update index file, find free recid
113 long recid = longStackTake(RECID_FREE_INDEX_SLOTS);
114 if(recid == 0){
115 //could not reuse recid, so create new one
116 if(indexSize%8!=0) throw new InternalError();
117 recid = indexSize/8;
118 indexSize+=8;
119 }
120
121 if(out.pos<MAX_RECORD_SIZE){
122 //get physical record
123 // first 16 bites is record size, remaining 48 bytes is record offset in phys file
124 final long indexValue = out.pos!=0?
125 freePhysRecTake(out.pos):0L;
126 writeIndexValToTransLog(recid, indexValue);
127
128 //write new phys data into trans log
129 writeOutToTransLog(out, recid, indexValue);
130 checkBufferRounding();
131 }else{
132 putLargeLinkedRecord(out, recid);
133 }
134
135
136
137 return recid-INDEX_OFFSET_START;
138 }finally {
139 lock.writeLock().unlock();
140 }
141 }catch(IOException e){
142 throw new IOError(e);
143 }
144 }
145
146 private void putLargeLinkedRecord(DataOutput2 out, long recid) throws IOException {
147 openLogIfNeeded();
148 //large size, needs to link multiple records together
149 //start splitting from end, so we can build up linked list
150 final int chunkSize = MAX_RECORD_SIZE-8;
151 int lastArrayPos = out.pos;
152 int arrayPos = out.pos - out.pos%chunkSize;
153 long lastChunkPhysId = 0;
154 ArrayList<Long> journalRefs = new ArrayList<Long>();
155 ArrayList<Long> physRecords = new ArrayList<Long>();
156 while(arrayPos>=0){
157 final int currentChunkSize = lastArrayPos-arrayPos;
158 byte[] b = new byte[currentChunkSize+8]; //TODO reuse byte[]
159 //append reference to prev physId
160 ByteBuffer.wrap(b).putLong(0, lastChunkPhysId);
161 //copy chunk
162 System.arraycopy(out.buf, arrayPos, b, 8, currentChunkSize);
163 //and write current chunk
164 lastChunkPhysId = freePhysRecTake(currentChunkSize+8);
165 physRecords.add(lastChunkPhysId);
166 //phys.putData(lastChunkPhysId&PHYS_OFFSET_MASK, b, b.length);
167
168 transLog.ensureAvailable(transLogOffset+10+currentChunkSize+8);
169 transLog.putLong(transLogOffset, WRITE_PHYS_ARRAY|(lastChunkPhysId&PHYS_OFFSET_MASK));
170 transLogOffset+=8;
171 transLog.putUnsignedShort(transLogOffset, currentChunkSize+8);
172 transLogOffset+=2;
173 final Long transLogReference = (((long)currentChunkSize)<<48)|(transLogOffset+8);
174 journalRefs.add(transLogReference);
175 transLog.putData(transLogOffset,b, b.length);
176 transLogOffset+=b.length;
177
178 checkBufferRounding();
179
180 lastArrayPos = arrayPos;
181 arrayPos-=chunkSize;
182 }
183 transLinkedPhysRecods.put(recid,physRecords);
184 writeIndexValToTransLog(recid, lastChunkPhysId);
185 long[] journalRefs2 = new long[journalRefs.size()];
186 for(int i=0;i<journalRefs2.length;i++){
187 journalRefs2[i] = journalRefs.get(i);
188 }
189 recordLogRefs.put(recid, journalRefs2);
190 }
191
192 protected void checkBufferRounding() throws IOException {
193 if(transLogOffset%Volume.BUF_SIZE > Volume.BUF_SIZE - MAX_RECORD_SIZE*2){
194 //position is to close to end of ByteBuffers (1GB)
195 //so start writing into new buffer
196 transLog.ensureAvailable(transLogOffset+8);
197 transLog.putLong(transLogOffset,WRITE_SKIP_BUFFER);
198 transLogOffset += Volume.BUF_SIZE-transLogOffset%Volume.BUF_SIZE;
199 }
200 }
201
202 protected void writeIndexValToTransLog(long recid, long indexValue) throws IOException {
203 //write new index value into transaction log
204 openLogIfNeeded();
205 transLog.ensureAvailable(transLogOffset+16);
206 transLog.putLong(transLogOffset, WRITE_INDEX_LONG | (recid * 8));
207 transLogOffset+=8;
208 transLog.putLong(transLogOffset, indexValue);
209 transLogOffset+=8;
210 recordIndexVals.put(recid,indexValue);
211 }
212
213 protected void writeOutToTransLog(DataOutput2 out, long recid, long indexValue) throws IOException {
214 openLogIfNeeded();
215 transLog.ensureAvailable(transLogOffset+10+out.pos);
216 transLog.putLong(transLogOffset, WRITE_PHYS_ARRAY|(indexValue&PHYS_OFFSET_MASK));
217 transLogOffset+=8;
218 transLog.putUnsignedShort(transLogOffset, out.pos);
219 transLogOffset+=2;
220 final long transLogReference = (((long)out.pos)<<48)|transLogOffset;
221 recordLogRefs.put(recid, new long[]{transLogReference}); //store reference to transaction log, so we can load data quickly
222 transLog.putData(transLogOffset,out.buf, out.pos);
223 transLogOffset+=out.pos;
224 }
225
226
227 @Override
228 public <A> A get(long recid, Serializer<A> serializer) {
229 if(serializer==null)throw new NullPointerException();
230 if(recid<=0) throw new IllegalArgumentException("recid");
231 recid+=INDEX_OFFSET_START;
232
233 try{
234 lock.readLock().lock();
235
236 long[] indexVals = recordLogRefs.get(recid);
237 if(indexVals!=null){
238 if(indexVals.length==1){
239 //single record
240 if(indexVals[0] == Long.MIN_VALUE)
241 return null; //was deleted
242 //record is in transaction log
243 return recordGet2(indexVals[0], transLog, serializer);
244 }else{
245 //read linked record from journal
246 //first calculate total size
247 int size = 0;
248 for(long physId:indexVals) size+= physId>>>48;
249 byte[] b = new byte[size];
250 //now load it in chunks
251 int pos = 0;
252 for(long physId:indexVals){
253 int curChunkSize = (int) (physId>>>48);
254 long offset = physId&PHYS_OFFSET_MASK;
255 DataInput2 in = transLog.getDataInput(offset, curChunkSize);
256 in.readFully(b,pos,curChunkSize);
257 pos+=curChunkSize;
258 }
259 if(size!=pos) throw new InternalError();
260 //now deserialize
261 DataInput2 in = new DataInput2(b);
262 A ret = serializer.deserialize(in, size);
263 if(in.pos!=size) throw new InternalError("Data were not fully read");
264 return ret;
265 }
266 }else{
267 //not in transaction log, read from file
268 final long indexValue = index.getLong(recid*8) ;
269 return recordGet2(indexValue, phys, serializer);
270 }
271 }catch(IOException e){
272 throw new IOError(e);
273 }finally{
274 lock.readLock().unlock();
275 }
276 }
277
278 @Override
279 public <A> void update(long recid, A value, Serializer<A> serializer) {
280 if(value==null||serializer==null) throw new NullPointerException();
281 if(recid<=0) throw new IllegalArgumentException("recid");
282 recid+=INDEX_OFFSET_START;
283
284 try{
285 DataOutput2 out = new DataOutput2();
286 serializer.serialize(out,value);
287
288 try{
289 lock.writeLock().lock();
290
291 //check if size has changed
292 long oldIndexVal = getIndexLong(recid);
293 long oldSize = oldIndexVal>>>48;
294
295 //check if we need to split new records into multiple one
296 if(out.pos<MAX_RECORD_SIZE){
297 if(oldSize == 0 && out.pos==0){
298 //do nothing
299 } else if(oldSize == out.pos ){
300 //size is the same, so just write new data
301 writeOutToTransLog(out, recid, oldIndexVal);
302 }else if(oldSize != 0 && out.pos==0){
303 //new record has zero size, just delete old phys one
304 freePhysRecPut(oldIndexVal);
305 writeIndexValToTransLog(recid, 0L);
306 }else{
307 //size has changed, so write into new location
308 final long newIndexValue = freePhysRecTake(out.pos);
309
310 writeOutToTransLog(out, recid, newIndexValue);
311 //update index file with new location
312 writeIndexValToTransLog(recid, newIndexValue);
313
314 //and set old phys record as free
315 unlinkPhysRecord(oldIndexVal,recid);
316 }
317 }else{
318 unlinkPhysRecord(oldIndexVal,recid); //unlink must be first to release currently used space
319 putLargeLinkedRecord(out, recid);
320 }
321
322
323 checkBufferRounding();
324 }finally {
325 lock.writeLock().unlock();
326 }
327 }catch(IOException e){
328 throw new IOError(e);
329 }
330
331 }
332
333 private long getIndexLong(long recid) {
334 Long v = recordIndexVals.get(recid);
335 return (v!=null) ? v :
336 index.getLong(recid * 8);
337 }
338
339 @Override
340 public <A> void delete(long recid, Serializer<A> serializer){
341 if(serializer==null) throw new NullPointerException();
342 if(recid<=0) throw new IllegalArgumentException("recid");
343 recid+=INDEX_OFFSET_START;
344
345 try{
346 lock.writeLock().lock();
347 openLogIfNeeded();
348
349 transLog.ensureAvailable(transLogOffset+8);
350 transLog.putLong(transLogOffset, WRITE_INDEX_LONG_ZERO | (recid*8));
351 transLogOffset+=8;
352 longStackPut(RECID_FREE_INDEX_SLOTS,recid);
353 recordLogRefs.put(recid, new long[]{Long.MIN_VALUE});
354 //check if is in transaction
355 long oldIndexVal = getIndexLong(recid);
356 recordIndexVals.put(recid,0L);
357 unlinkPhysRecord(oldIndexVal,recid);
358
359
360 checkBufferRounding();
361
362 }catch(IOException e){
363 throw new IOError(e);
364 }finally {
365 lock.writeLock().unlock();
366 }
367 }
368
369
370 @Override
371 public void close() {
372 super.close();
373
374 if(transLog!=null){
375 transLog.sync();
376 transLog.close();
377 if(deleteFilesOnExit){
378 transLog.deleteFile();
379 }
380 }
381
382 transLog = null;
383 //TODO delete trans log logic
384 }
385
386 @Override
387 public void commit() {
388 try{
389 lock.writeLock().lock();
390
391 //dump long stack pages
392 LongMap.LongMapIterator<long[]> iter = longStackPages.longMapIterator();
393 while(iter.moveToNext()){
394 transLog.ensureAvailable(transLogOffset+8+2+LONG_STACK_PAGE_SIZE);
395 transLog.putLong(transLogOffset, WRITE_PHYS_ARRAY|iter.key());
396 transLogOffset+=8;
397 transLog.putUnsignedShort(transLogOffset, LONG_STACK_PAGE_SIZE);
398 transLogOffset+=2;
399 for(long l:iter.value()){
400 transLog.putLong(transLogOffset, l);
401 transLogOffset+=8;
402 }
403 checkBufferRounding();
404 }
405
406 //update physical and logical filesize
407 writeIndexValToTransLog(RECID_CURRENT_PHYS_FILE_SIZE, physSize);
408 writeIndexValToTransLog(RECID_CURRENT_INDEX_FILE_SIZE, indexSize);
409
410
411 //seal log file
412 transLog.ensureAvailable(transLogOffset+8);
413 transLog.putLong(transLogOffset, WRITE_SEAL);
414 transLogOffset+=8;
415 //flush log file
416 transLog.sync();
417 //and write mark it was sealed
418 transLog.putLong(8, LOG_SEAL);
419 transLog.sync();
420
421 replayLogFile();
422 reloadIndexFile();
423
424 }catch(IOException e){
425 throw new IOError(e);
426 }finally{
427 lock.writeLock().unlock();
428 }
429 }
430
431 protected void replayLogFile(){
432
433 writeLock_checkLocked();
434 transLogOffset = 0;
435
436 if(transLog!=null){
437 transLog.sync();
438 }
439
440
441 //read headers
442 if(transLog.isEmpty() || transLog.getLong(0)!=HEADER || transLog.getLong(8) !=LOG_SEAL){
443 //wrong headers, discard log
444 transLog.close();
445 transLog.deleteFile();
446 transLog = null;
447 return;
448 }
449
450
451 //all good, start replay
452 transLogOffset=16;
453 long ins = transLog.getLong(transLogOffset);
454 transLogOffset+=8;
455
456 while(ins!=WRITE_SEAL && ins!=0){
457
458 final long offset = ins&PHYS_OFFSET_MASK;
459 ins -=offset;
460
461 if(ins == WRITE_INDEX_LONG_ZERO){
462 index.ensureAvailable(offset+8);
463 index.putLong(offset, 0L);
464 }else if(ins == WRITE_INDEX_LONG){
465 final long value = transLog.getLong(transLogOffset);
466 transLogOffset+=8;
467 index.ensureAvailable(offset+8);
468 index.putLong(offset, value);
469 }else if(ins == WRITE_PHYS_LONG){
470 final long value = transLog.getLong(transLogOffset);
471 transLogOffset+=8;
472 phys.ensureAvailable(offset+8);
473 phys.putLong(offset, value);
474 }else if(ins == WRITE_PHYS_ARRAY){
475 final int size = transLog.getUnsignedShort(transLogOffset);
476 transLogOffset+=2;
477 //transfer byte[] directly from log file without copying into memory
478 DataInput2 input = transLog.getDataInput(transLogOffset, size);
479 synchronized (input.buf){
480 input.buf.position(input.pos);
481 input.buf.limit(input.pos+size);
482 phys.ensureAvailable(offset+size);
483 phys.putData(offset, input.buf);
484 input.buf.clear();
485 }
486 transLogOffset+=size;
487 }else if(ins == WRITE_SKIP_BUFFER){
488 transLogOffset += Volume.BUF_SIZE-transLogOffset%Volume.BUF_SIZE;
489 }else{
490 throw new InternalError("unknown trans log instruction: "+(ins>>>48));
491 }
492
493 ins = transLog.getLong(transLogOffset);
494 transLogOffset+=8;
495 }
496 transLogOffset=0;
497
498 //flush dbs
499 phys.sync();
500 index.sync();
501 //and discard log
502 transLog.putLong(0, 0);
503 transLog.putLong(8, 0); //destroy seal to prevent log file from being replayed
504 transLog.close();
505 transLog.deleteFile();
506 transLog = null;
507 }
508
509
510 @Override
511 public void rollback() {
512 lock.writeLock().lock();
513 try{
514 //discard trans log
515 if(transLog!=null){
516 transLog.close();
517 transLog.deleteFile();
518 transLog = null;
519 }
520
521 reloadIndexFile();
522 }finally{
523 lock.writeLock().unlock();
524 }
525
526 }
527
528 @Override
529 public void compact() {
530 lock.writeLock().lock();
531 try{
532 if(transLog!=null && !transLog.isEmpty())
533 throw new IllegalAccessError("Journal not empty; commit first, than compact");
534 super.compact();
535 }finally {
536 lock.writeLock().unlock();
537 }
538 }
539
540
541 private long[] getLongStackPage(final long physOffset, boolean read){
542 long[] buf = longStackPages.get(physOffset);
543 if(buf == null){
544 buf = new long[LONG_STACK_NUM_OF_RECORDS_PER_PAGE+1];
545 if(read)
546 for(int i=0;i<buf.length;i++){
547 buf[i] = phys.getLong(physOffset+i*8);
548 }
549 longStackPages.put(physOffset,buf);
550 }
551 return buf;
552 }
553
554 @Override
555 protected long longStackTake(final long listRecid) throws IOException {
556 final long dataOffset = getIndexLong(listRecid) & PHYS_OFFSET_MASK;
557 if(dataOffset == 0)
558 return 0; //there is no such list, so just return 0
559
560 writeLock_checkLocked();
561
562 long[] buf = getLongStackPage(dataOffset,true);
563
564 final int numberOfRecordsInPage = (int) (buf[0]>>>(8*7));
565
566
567 if(numberOfRecordsInPage<=0)
568 throw new InternalError();
569 if(numberOfRecordsInPage>LONG_STACK_NUM_OF_RECORDS_PER_PAGE) throw new InternalError();
570
571 final long ret = buf[numberOfRecordsInPage];
572
573 final long previousListPhysid = buf[0] & PHYS_OFFSET_MASK;
574
575 //was it only record at that page?
576 if(numberOfRecordsInPage == 1){
577 //yes, delete this page
578 long value = previousListPhysid !=0 ?
579 previousListPhysid | (((long) LONG_STACK_PAGE_SIZE) << 48) :
580 0L;
581 //update index so it points to previous (or none)
582 writeIndexValToTransLog(listRecid, value);
583
584 //put space used by this page into free list
585 longStackPages.remove(dataOffset); //TODO write zeroes to phys file
586 freePhysRecPut(dataOffset | (((long)LONG_STACK_PAGE_SIZE)<<48));
587 }else{
588 //no, it was not last record at this page, so just decrement the counter
589 buf[0] = previousListPhysid | ((1L*numberOfRecordsInPage-1L)<<(8*7));
590 }
591 return ret;
592
593 }
594
595 @Override
596 protected void longStackPut(final long listRecid, final long offset) throws IOException {
597 writeLock_checkLocked();
598
599 //index position was cleared, put into free index list
600 final long listPhysid2 =getIndexLong(listRecid) & PHYS_OFFSET_MASK;
601
602 if(listPhysid2 == 0){ //empty list?
603 //yes empty, create new page and fill it with values
604 final long listPhysid = freePhysRecTake(LONG_STACK_PAGE_SIZE) &PHYS_OFFSET_MASK;
605 long[] buf = getLongStackPage(listPhysid,false);
606 if(listPhysid == 0) throw new InternalError();
607 //set number of free records in this page to 1
608 buf[0] = 1L<<(8*7);
609 //set record
610 buf[1] = offset;
611 //and update index file with new page location
612 writeIndexValToTransLog(listRecid, (((long) LONG_STACK_PAGE_SIZE) << 48) | listPhysid);
613 }else{
614 long[] buf = getLongStackPage(listPhysid2,true);
615 final int numberOfRecordsInPage = (int) (buf[0]>>>(8*7));
616 if(numberOfRecordsInPage == LONG_STACK_NUM_OF_RECORDS_PER_PAGE){ //is current page full?
617 //yes it is full, so we need to allocate new page and write our number there
618 final long listPhysid = freePhysRecTake(LONG_STACK_PAGE_SIZE) &PHYS_OFFSET_MASK;
619 long[] bufNew = getLongStackPage(listPhysid,false);
620 if(listPhysid == 0) throw new InternalError();
621 //final ByteBuffers dataBuf = dataBufs[((int) (listPhysid / BUF_SIZE))];
622 //set location to previous page
623 //set number of free records in this page to 1
624 bufNew[0] = listPhysid2 | (1L<<(8*7));
625 //set free record
626 bufNew[1] = offset;
627 //and update index file with new page location
628 writeIndexValToTransLog(listRecid,(((long) LONG_STACK_PAGE_SIZE) << 48) | listPhysid);
629 }else{
630 //there is space on page, so just write released recid and increase the counter
631 buf[1+numberOfRecordsInPage] = offset;
632 buf[0] = (buf[0]&PHYS_OFFSET_MASK) | ((1L*numberOfRecordsInPage+1L)<<(8*7));
633 }
634 }
635 }
636
637
638
639 @Override
640 protected long freePhysRecTake(final int requiredSize) throws IOException {
641 writeLock_checkLocked();
642
643 if(requiredSize<=0) throw new InternalError();
644
645 long freePhysRec = appendOnly? 0L:
646 findFreePhysSlot(requiredSize);
647 if(freePhysRec!=0){
648 return freePhysRec;
649 }
650
651 //No free records found, so lets increase the file size.
652 //We need to take case of growing ByteBuffers.
653 // Also max size of ByteBuffers is 2GB, so we need to use multiple ones
654
655 final long oldFileSize = physSize;
656 if(oldFileSize <=0) throw new InternalError("illegal file size:"+oldFileSize);
657
658 //check if new record would be overflowing BUF_SIZE
659 if(oldFileSize%Volume.BUF_SIZE+requiredSize<=Volume.BUF_SIZE){
660 //no, so just increase file size
661 physSize+=requiredSize;
662 //so just increase buffer size
663
664 //and return this
665 return (((long)requiredSize)<<48) | oldFileSize;
666 }else{
667 //new size is overlapping 2GB ByteBuffers size
668 //so we need to create empty record for 'padding' size to 2GB
669
670 final long freeSizeToCreate = Volume.BUF_SIZE - oldFileSize%Volume.BUF_SIZE;
671 if(freeSizeToCreate == 0) throw new InternalError();
672
673 final long nextBufferStartOffset = oldFileSize + freeSizeToCreate;
674 if(nextBufferStartOffset%Volume.BUF_SIZE!=0) throw new InternalError();
675
676 //increase the disk size
677 physSize += freeSizeToCreate + requiredSize;
678
679 //mark 'padding' free record
680 freePhysRecPut((freeSizeToCreate<<48)|oldFileSize);
681
682 //and finally return position at beginning of new buffer
683 return (((long)requiredSize)<<48) | nextBufferStartOffset;
684 }
685
686 }
687
688 @Override
689 protected void unlinkPhysRecord(long indexVal, long recid) throws IOException {
690 if(indexVal == 0) return;
691
692 ArrayList<Long> linkedInTrans = transLinkedPhysRecods.remove(recid);
693 if(linkedInTrans!=null){
694 for(Long l:linkedInTrans){
695 freePhysRecPut(l);
696 }
697 return;
698 }
699
700 if((indexVal>>>48)<MAX_RECORD_SIZE){ //check size
701 //single record
702 freePhysRecPut(indexVal);
703 return;
704 }
705
706 while(indexVal!=0){
707 freePhysRecPut(indexVal);
708 final long offset = indexVal & PHYS_OFFSET_MASK;
709 indexVal = phys.getLong(offset); //read next value
710 }
711 }
712
713}
Note: See TracBrowser for help on using the repository browser.