Browse files

Reworked free logic rowid manager the same way as previous commit. No…

…w it has constant update/write time no mather how store is fragmented.
  • Loading branch information...
1 parent b336b49 commit 7752e18743e2fd23f466af45d146f9f380f17319 @dan-g dan-g committed Apr 8, 2012
View
87 src/main/java/net/kotek/jdbm/BlockIo.java
@@ -435,92 +435,5 @@ void dataPageSetFirst(short value) {
- short FreeLogicalRowId_getCount() {
- return readShort(Magic.FreeLogicalRowId_O_COUNT);
- }
-
- private void FreeLogicalRowId_setCount(short i) {
- writeShort(Magic.FreeLogicalRowId_O_COUNT, i);
- }
-
- boolean FreeLogicalRowId_isFree(int slot) {
- return !FreeLogicalRowId_isAllocated(slot);
- }
-
-
- boolean FreeLogicalRowId_isAllocated(int slot) {
- //return get(slot).getBlock() > 0;
- return pageHeaderGetLocation(FreeLogicalRowId_slotToOffset(slot)) > 0;
- }
-
-
- short FreeLogicalRowId_slotToOffset(int slot) {
- return (short) (Magic.FreeLogicalRowId_O_FREE +
- (slot * Magic.PhysicalRowId_SIZE));
- }
-
-
-
-
- /**
- * Frees a slot
- */
- void FreeLogicalRowId_free(short slot) {
- pageHeaderSetLocation(FreeLogicalRowId_slotToOffset(slot), Location.toLong(0, (short) 0));
- //get(slot).setBlock(0);
- FreeLogicalRowId_setCount((short) ( FreeLogicalRowId_getCount() - 1));
-
- // update previousFoundFree if the freed slot is before what we've found in the past
- if (slot < readShort(FreeLogicalRowId_O_LAST_FREE))
- writeShort(FreeLogicalRowId_O_LAST_FREE,slot);
- }
-
- /**
- * Allocates a slot
- */
- short FreeLogicalRowId_alloc(short slot) {
- FreeLogicalRowId_setCount((short) ( FreeLogicalRowId_getCount() + 1));
- short pos = FreeLogicalRowId_slotToOffset(slot);
- pageHeaderSetLocation(pos, Location.toLong(-1, (short) 0));
- //get(slot).setBlock(-1);
-
- // update previousFoundAllocated if the newly allocated slot is before what we've found in the past
- if (slot < readShort(FreeLogicalRowId_O_LAST_ALOC))
- writeShort(FreeLogicalRowId_O_LAST_ALOC,slot);
-
- return pos;
- }
-
-
-
- short FreeLogicalRowId_getFirstFree() {
- short previousFoundFree = readShort(FreeLogicalRowId_O_LAST_FREE);
- for (; previousFoundFree < Magic.FreeLogicalRowId_ELEMS_PER_PAGE; previousFoundFree++) {
- if ( FreeLogicalRowId_isFree(previousFoundFree)){
- writeShort(FreeLogicalRowId_O_LAST_FREE,previousFoundFree);
- return previousFoundFree;
- }
- }
- return -1;
- }
-
- short FreeLogicalRowId_getFirstAllocated() {
- short previousFoundAllocated = readShort(FreeLogicalRowId_O_LAST_ALOC);
- for (; previousFoundAllocated < Magic.FreeLogicalRowId_ELEMS_PER_PAGE; previousFoundAllocated++) {
- if ( FreeLogicalRowId_isAllocated(previousFoundAllocated)){
- writeShort(FreeLogicalRowId_O_LAST_ALOC,previousFoundAllocated);
- return previousFoundAllocated;
- }
- }
- return -1;
- }
-
- public long FreeLogicalRowId_slotToLocation(int slot) {
- short pos = FreeLogicalRowId_slotToOffset(slot);
- return pageHeaderGetLocation(pos);
- }
-
-
-
}
View
127 src/main/java/net/kotek/jdbm/LogicalRowIdManager.java
@@ -32,6 +32,12 @@
private int freeRecordsInTransSize = 0;
+ /** number of free logical rowids on logical free page, is SHORT*/
+ static final int OFFSET_FREE_COUNT = Magic.PAGE_HEADER_SIZE;
+ static final int FREE_HEADER_SIZE = Magic.PAGE_HEADER_SIZE + Magic.SZ_SHORT;
+ /** maximal number of free logical per page */
+ static final int FREE_RECORDS_PER_PAGE = (Storage.BLOCK_SIZE-FREE_HEADER_SIZE)/6;
+
/**
* Creates a log rowid manager using the indicated record file and page manager
@@ -134,57 +140,45 @@ long fetch(long logicalrowid) throws IOException {
}
void commit() throws IOException {
+ if(freeRecordsInTransSize==0) return;
+
+ long freeRecPageId = pageman.getLast(Magic.FREELOGIDS_PAGE);
+ if(freeRecPageId == 0){
+ //allocate new
+ freeRecPageId = pageman.allocate(Magic.FREELOGIDS_PAGE);
+ }
+ BlockIo freeRecPage = file.get(freeRecPageId);
//write all uncommited free records
- int rowIdPos = 0;
-
- //iterate over filled pages
- for (long current = pageman.getFirst(Magic.FREELOGIDS_PAGE); current != 0; current = pageman.getNext(current)) {
-
- final BlockIo fp = file.get(current);
- short slot = fp.FreeLogicalRowId_getFirstFree();
- //iterate over free slots in page and fill them
- while (slot != -1 && rowIdPos < freeRecordsInTransSize) {
- final long rowid = freeRecordsInTransRowid[rowIdPos++];
- final short freePhysRowId = fp.FreeLogicalRowId_alloc(slot);
- fp.pageHeaderSetLocation(freePhysRowId, rowid);
- slot = fp.FreeLogicalRowId_getFirstFree();
+ for(int rowPos = 0;rowPos<freeRecordsInTransSize;rowPos++){
+ short count = freeRecPage.readShort(OFFSET_FREE_COUNT);
+ if(count == FREE_RECORDS_PER_PAGE){
+ //allocate new free recid page
+ file.release(freeRecPage);
+ freeRecPageId = pageman.allocate(Magic.FREELOGIDS_PAGE);
+ freeRecPage = file.get(freeRecPageId);
+ freeRecPage.writeShort(FREE_RECORDS_PER_PAGE, (short)0);
+ count = 0;
}
- file.release(current, true);
- if (!(rowIdPos < freeRecordsInTransSize))
- break;
- }
+ final int offset = (count ) *6 + FREE_HEADER_SIZE;
+ //write free recid and increase counter
+ freeRecPage.writeSixByteLong(offset,freeRecordsInTransRowid[rowPos]);
+ count++;
+ freeRecPage.writeShort(OFFSET_FREE_COUNT, count);
- //now we propably filled all already allocated pages,
- //time to start allocationg new pages
- while (rowIdPos < freeRecordsInTransSize) {
- //allocate new page
- long freePage = pageman.allocate(Magic.FREELOGIDS_PAGE);
- BlockIo fp = file.get(freePage);
- short slot = fp.FreeLogicalRowId_getFirstFree();
- //iterate over free slots in page and fill them
- while (slot != -1 && rowIdPos < freeRecordsInTransSize) {
- long rowid = freeRecordsInTransRowid[rowIdPos++];
- short freePhysRowId = fp.FreeLogicalRowId_alloc(slot);
- fp.pageHeaderSetLocation(freePhysRowId, rowid);
- slot = fp.FreeLogicalRowId_getFirstFree();
- }
- file.release(freePage, true);
- if (!(rowIdPos < freeRecordsInTransSize))
- break;
}
+ file.release(freeRecPage);
- if (rowIdPos < freeRecordsInTransSize)
- throw new InternalError();
+ clearFreeRecidsInTransaction();
+ }
+
+ private void clearFreeRecidsInTransaction() {
if(freeRecordsInTransRowid.length>128)
freeRecordsInTransRowid = new long[4];
freeRecordsInTransSize = 0;
-
}
void rollback() throws IOException {
- if(freeRecordsInTransRowid.length>128)
- freeRecordsInTransRowid = new long[4];
- freeRecordsInTransSize = 0;
+ clearFreeRecidsInTransaction();
}
@@ -197,31 +191,34 @@ long getFreeSlot() throws IOException {
return freeRecordsInTransRowid[--freeRecordsInTransSize];
}
- // Loop through the free Logical rowid list until we get
- // the first rowid.
- long retval = 0;
- for (long current = pageman.getFirst(Magic.FREELOGIDS_PAGE); current != 0; current = pageman.getNext(current)) {
- BlockIo fp = file.get(current);
- short slot = fp.FreeLogicalRowId_getFirstAllocated();
- if (slot != -1) {
- // got one!
- retval = fp.FreeLogicalRowId_slotToLocation(slot);
-
- fp.FreeLogicalRowId_free(slot);
- if (fp.FreeLogicalRowId_getCount() == 0) {
- // page became empty - free it
- file.release(current, false);
- pageman.free(Magic.FREELOGIDS_PAGE, current);
- } else
- file.release(current, true);
-
- return retval;
- } else {
- // no luck, go to next page
- file.release(current, false);
- }
+ final long logicFreePageId = pageman.getLast(Magic.FREELOGIDS_PAGE);
+ if(logicFreePageId == 0) {
+ return 0;
+ }
+ BlockIo logicFreePage = file.get(logicFreePageId);
+ short recCount = logicFreePage.readShort(OFFSET_FREE_COUNT);
+ if(recCount <= 0){
+ throw new InternalError();
}
- return 0;
+
+
+ final int offset = (recCount -1) *6 + FREE_HEADER_SIZE;
+ final long ret = logicFreePage.readSixByteLong(offset);
+
+ recCount--;
+
+ if(recCount>0){
+ //decrease counter and zero out old record
+ logicFreePage.writeSixByteLong(offset,0);
+ logicFreePage.writeShort(OFFSET_FREE_COUNT, recCount);
+ file.release(logicFreePage);
+ }else{
+ //release this page
+ file.release(logicFreePage);
+ pageman.free(Magic.FREELOGIDS_PAGE,logicFreePageId);
+ }
+
+ return ret;
}
/**
@@ -230,7 +227,7 @@ long getFreeSlot() throws IOException {
void putFreeSlot(long rowid) throws IOException {
//ensure capacity
if(freeRecordsInTransSize == freeRecordsInTransRowid.length)
- freeRecordsInTransRowid = Arrays.copyOf(freeRecordsInTransRowid, freeRecordsInTransRowid.length * 2);
+ freeRecordsInTransRowid = Arrays.copyOf(freeRecordsInTransRowid, freeRecordsInTransRowid.length * 4);
//add record and increase size
freeRecordsInTransRowid[freeRecordsInTransSize]=rowid;
freeRecordsInTransSize++;
View
10 src/main/java/net/kotek/jdbm/Magic.java
@@ -100,16 +100,6 @@
- // offsets
- short FreeLogicalRowId_O_COUNT = Magic.PAGE_HEADER_SIZE; // short count
- /** keeps track of the most recent found free slot so we can locate it again quickly*/
- short FreeLogicalRowId_O_LAST_FREE = (short) (FreeLogicalRowId_O_COUNT + Magic.SZ_SHORT);
- /**keeps track of the most recent found allocated slot so we can locate it again quickly*/
- short FreeLogicalRowId_O_LAST_ALOC = (short) (FreeLogicalRowId_O_LAST_FREE + Magic.SZ_SHORT);
- short FreeLogicalRowId_O_FREE = (short) (FreeLogicalRowId_O_LAST_ALOC + Magic.SZ_SHORT);
- short FreeLogicalRowId_ELEMS_PER_PAGE = (short) ((Storage.BLOCK_SIZE - FreeLogicalRowId_O_FREE) / Magic.PhysicalRowId_SIZE);
-
-
}
View
4 src/main/java/net/kotek/jdbm/PhysicalFreeRowIdManager.java
@@ -81,9 +81,7 @@ long getFreeRecord(final int size) throws IOException {
short recidCount = slotPage.readShort(OFFSET_SLOT_PAGE_REC_COUNT);
if(recidCount<=0){
- file.release(slotPage);
- file.release(root);
- return 0;
+ throw new InternalError();
}
final int offset = (recidCount-1) * 6 + SLOT_PAGE_HEADER_SIZE;
View
70 src/test/java/net/kotek/jdbm/FreeLogicalRowIdPageTest.java
@@ -1,70 +0,0 @@
-/*******************************************************************************
- * Copyright 2010 Cees De Groot, Alex Boisvert, Jan Kotek
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- ******************************************************************************/
-
-package net.kotek.jdbm;
-
-import junit.framework.TestCase;
-
-public class FreeLogicalRowIdPageTest extends TestCase {
-
-
-
- /**
- * Test basics
- */
- public void testBasics() throws Exception {
- byte[] data = new byte[Storage.BLOCK_SIZE];
- BlockIo page = new BlockIo(0, data);
-
- // we have a completely empty page.
- assertEquals("zero count", 0, page.FreeLogicalRowId_getCount());
-
- // three allocs
- short id = page.FreeLogicalRowId_alloc((short) 0);
- id = page.FreeLogicalRowId_alloc((short) 1);
- id = page.FreeLogicalRowId_alloc((short) 2);
- assertEquals("three count", 3, page.FreeLogicalRowId_getCount());
-
- // setup last id (2)
- page.pageHeaderSetLocation(id, Location.toLong(1, (short) 2));
-
-
- // two frees
- page.FreeLogicalRowId_free((short) 0);
- page.FreeLogicalRowId_free((short) 1);
- assertEquals("one left count", 1, page.FreeLogicalRowId_getCount());
- assertTrue("isfree 0", page.FreeLogicalRowId_isFree(0));
- assertTrue("isfree 1", page.FreeLogicalRowId_isFree(1));
- assertTrue("isalloc 2", page.FreeLogicalRowId_isAllocated(2));
-
- // now, create a new page over the data and check whether
- // it's all the same.
- page = new BlockIo(0,data);
-
- assertEquals("2: one left count", 1, page.FreeLogicalRowId_getCount());
- assertTrue("2: isfree 0", page.FreeLogicalRowId_isFree(0));
- assertTrue("2: isfree 1", page.FreeLogicalRowId_isFree(1));
- assertTrue("2: isalloc 2", page.FreeLogicalRowId_isAllocated(2));
-
- id = page.FreeLogicalRowId_slotToOffset(2);
- long loc = page.pageHeaderGetLocation(id);
- assertEquals("block", 1, Location.getBlock(loc));
- assertEquals("offset", 2, Location.getOffset(loc));
-
- }
-
-
-}

0 comments on commit 7752e18

Please sign in to comment.