[Joafip-svn] SF.net SVN: joafip:[2964] trunk/joafip-heapfile
Brought to you by:
luc_peuvrier
|
From: <luc...@us...> - 2011-11-12 16:53:44
|
Revision: 2964
http://joafip.svn.sourceforge.net/joafip/?rev=2964&view=rev
Author: luc_peuvrier
Date: 2011-11-12 16:53:35 +0000 (Sat, 12 Nov 2011)
Log Message:
-----------
refactoring. Added block data manager for tests
Modified Paths:
--------------
trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/record/entity/DataRecordIdentifier.java
trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/service/HeapFileDataManager.java
trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/service/IHeapDataManager.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/AbstractTestHeapDataManager.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapFileCheckerDataManager.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapMemoryDataManagerMock.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapMultiFileDataManager.java
Added Paths:
-----------
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/BlockDataManagerHeader.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/DataBlock.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/AbstractTestHeapDataManagerImpl.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/BlockDataManager.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/DualWrapDataManager.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestBlockDataManager.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapFileDataManager.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapFileDataManagerBackup.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapFileDataManagerFreeing.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapFileDataMgrMemoryLeak.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapFileDataMgrWithScenario.java
Removed Paths:
-------------
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapDataManager.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapDataManagerBackup.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapDataManagerFreeing.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapDataMgrMemoryLeak.java
trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/TestHeapDataMgrWithScenario.java
Property Changed:
----------------
trunk/joafip-heapfile/
Property changes on: trunk/joafip-heapfile
___________________________________________________________________
Modified: svn:ignore
- target
.settings
.classpath
.project
.pmd
logs
+ target
.settings
.classpath
.project
.pmd
logs
runtime
Modified: trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/record/entity/DataRecordIdentifier.java
===================================================================
--- trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/record/entity/DataRecordIdentifier.java 2011-11-12 16:49:48 UTC (rev 2963)
+++ trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/record/entity/DataRecordIdentifier.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -45,7 +45,7 @@
* create the first data record identifier: #0
*
*/
- private DataRecordIdentifier() {
+ public DataRecordIdentifier() {
super();
this.value = 0;
}
Modified: trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/service/HeapFileDataManager.java
===================================================================
--- trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/service/HeapFileDataManager.java 2011-11-12 16:49:48 UTC (rev 2963)
+++ trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/service/HeapFileDataManager.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -1113,6 +1113,7 @@
* @throws HeapException
*/
@Fortest
+ @Override
public long getLastRecordPositionInFile() throws HeapException {
final long lastRecordPositionInFile = heapElementManager
.getLastRecordPositionInFile();
@@ -1120,6 +1121,7 @@
}
@Fortest
+ @Override
public long getRecordPositionInfile(final DataRecordIdentifier identifier)
throws HeapException {
final HeapIdNode heapIdNode = idNodeSearchMayBeNotExist(identifier);
Modified: trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/service/IHeapDataManager.java
===================================================================
--- trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/service/IHeapDataManager.java 2011-11-12 16:49:48 UTC (rev 2963)
+++ trunk/joafip-heapfile/src/main/java/net/sf/joafip/heapfile/service/IHeapDataManager.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -162,6 +162,7 @@
*
* @param dataRecordIdentifier
* data record to delete identifier
+ * @return true if record existed and then deleted
* @throws HeapException
*/
boolean deleteDataRecord(DataRecordIdentifier dataRecordIdentifier)
@@ -175,6 +176,7 @@
* @return data record identifier of first data record removed
* @throws HeapException
*/
+ //FIXMELUC _____________________to test or remove or add more
DataRecordIdentifier removeFirstDataRecord() throws HeapException;
/**
@@ -283,4 +285,11 @@
*/
@Fortest
Iterator<DataRecordIdentifier> dataRecordIterator() throws HeapException;
+
+ @Fortest
+ long getRecordPositionInfile(DataRecordIdentifier identifier)
+ throws HeapException;
+
+ @Fortest
+ long getLastRecordPositionInFile() throws HeapException;
}
Added: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/BlockDataManagerHeader.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/BlockDataManagerHeader.java (rev 0)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/BlockDataManagerHeader.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2011 Luc Peuvrier
+ *
+ * This file is a part of JOAFIP.
+ *
+ * JOAFIP is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE
+ * Licensed under the LGPL License, Version 3, 29 June 2007 (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.gnu.org/licenses/lgpl.html
+ *
+ * JOAFIP is distributed in the hope that it will be useful, but
+ * 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.sf.joafip.heapfile.entity;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import net.sf.joafip.DoNotTransform;
+import net.sf.joafip.NotStorableClass;
+import net.sf.joafip.heapfile.record.entity.DataRecordIdentifier;
+import net.sf.joafip.heapfile.service.HeapException;
+
+/**
+ *
+ * @author luc peuvrier
+ *
+ */
+@NotStorableClass
+@DoNotTransform
+public class BlockDataManagerHeader implements Serializable {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8579792598621073099L;
+
+ private int blockLength;
+
+ private DataRecordIdentifier nextIdentifier;
+
+ private long dataLength;
+
+ private int numberOfDataRecord;
+
+ public int getBlockLength() {
+ return blockLength;
+ }
+
+ public void setBlockLength(final int blockLength) {
+ this.blockLength = blockLength;
+ }
+
+ public DataRecordIdentifier getNextIdentifier() {
+ return nextIdentifier;
+ }
+
+ public void setNextIdentifier(final DataRecordIdentifier nextIdentifier) {
+ this.nextIdentifier = nextIdentifier;
+ }
+
+ public long getDataLength() {
+ return dataLength;
+ }
+
+ public void setDataLength(final long dataLength) {
+ this.dataLength = dataLength;
+ }
+
+ public int getNumberOfDataRecord() {
+ return numberOfDataRecord;
+ }
+
+ public void setNumberOfDataRecord(final int numberOfDataRecord) {
+ this.numberOfDataRecord = numberOfDataRecord;
+ }
+
+ public void decrementNumberOfDataRecord() {
+ numberOfDataRecord--;
+ }
+
+ public void incrementNumberOfDataRecord() {
+ numberOfDataRecord++;
+ }
+
+ public void set(final byte[] data) throws HeapException {
+ try {
+ final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
+ data);
+ final ObjectInputStream objectInputStream = new ObjectInputStream(
+ byteArrayInputStream);
+ final BlockDataManagerHeader header = (BlockDataManagerHeader) objectInputStream
+ .readObject();
+ objectInputStream.close();
+ set(header);
+ } catch (IOException exception) {
+ throw new HeapException(exception);
+ } catch (ClassNotFoundException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ private void set(final BlockDataManagerHeader header) {
+ this.dataLength = header.dataLength;
+ this.nextIdentifier = header.nextIdentifier;
+ this.blockLength=header.blockLength;
+ this.numberOfDataRecord=header.numberOfDataRecord;
+ }
+
+ public byte[] get() throws HeapException {
+ try {
+ final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ final ObjectOutputStream objectOutputStream = new ObjectOutputStream(
+ byteArrayOutputStream);
+ objectOutputStream.writeObject(this);
+ objectOutputStream.close();
+ return byteArrayOutputStream.toByteArray();
+ } catch (IOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ private void writeObject(final ObjectOutputStream out) throws IOException {
+ out.writeInt(blockLength);
+ out.writeLong(dataLength);
+ out.writeLong(nextIdentifier.value);
+ out.writeInt(numberOfDataRecord);
+ }
+
+ private void readObject(final ObjectInputStream input) throws IOException,
+ ClassNotFoundException {
+ blockLength=input.readInt();
+ dataLength = input.readLong();
+ final long value = input.readLong();
+ nextIdentifier = new DataRecordIdentifier(value);
+ numberOfDataRecord=input.readInt();
+ }
+}
Added: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/DataBlock.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/DataBlock.java (rev 0)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/entity/DataBlock.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011 Luc Peuvrier
+ *
+ * This file is a part of JOAFIP.
+ *
+ * JOAFIP is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE
+ * Licensed under the LGPL License, Version 3, 29 June 2007 (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.gnu.org/licenses/lgpl.html
+ *
+ * JOAFIP is distributed in the hope that it will be useful, but
+ * 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.sf.joafip.heapfile.entity;
+
+/**
+ *
+ * @author luc peuvrier
+ *
+ */
+public class DataBlock {
+
+ private final long positionInFile;
+
+ private boolean toWrite;
+
+ private final byte[] data;
+
+ public DataBlock(final long positionInFile,final boolean toWrite,final byte[] data) { //NOPMD
+ super();
+ this.positionInFile = positionInFile;
+ this.toWrite = toWrite;
+ this.data = data;
+ }
+
+ public boolean isToWrite() {
+ return toWrite;
+ }
+
+ public void setToWrite(final boolean toWrite) {
+ this.toWrite = toWrite;
+ }
+
+ public long getPositionInFile() {
+ return positionInFile;
+ }
+
+ public byte[] getData() {
+ return data; //NOPMD
+ }
+}
Modified: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/AbstractTestHeapDataManager.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/AbstractTestHeapDataManager.java 2011-11-12 16:49:48 UTC (rev 2963)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/AbstractTestHeapDataManager.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -46,7 +46,7 @@
protected String tempFilePath;
- protected HeapFileDataManager heapDataManager; // NOPMD
+ protected IHeapDataManager heapDataManager; // NOPMD
protected File dataFile; // NOPMD
@@ -116,7 +116,7 @@
* @throws HeapException
*
*/
- protected void createHeap(final boolean removeFile) throws HeapException {
+ protected void createHeapFileDataManager(final boolean removeFile) throws HeapException {
final HeapFileSetup setup = new HeapFileSetup(dataFile,
true/* crashSafeMode */, false/* useCacheMode */,
false/* deleteRenaming */, false/* clearResizeFile */, 1, 0,
@@ -127,6 +127,15 @@
heapDataManager.startService(removeFile);
}
+ protected void createBlockDataManager(final boolean removeFile) throws HeapException {
+ heapDataManager = new BlockDataManager(dataFilePath,20000);
+ heapDataManager.startService(removeFile);
+ }
+
+ protected abstract void createHeap(final boolean removeFile) throws HeapException;
+
+ protected abstract boolean manageFreeRecord();
+
/**
* @throws HeapException
*
Added: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/AbstractTestHeapDataManagerImpl.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/AbstractTestHeapDataManagerImpl.java (rev 0)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/AbstractTestHeapDataManagerImpl.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -0,0 +1,624 @@
+/*
+ * Copyright 2011 Luc Peuvrier
+ *
+ * This file is a part of JOAFIP.
+ *
+ * JOAFIP is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE
+ * Licensed under the LGPL License, Version 3, 29 June 2007 (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.gnu.org/licenses/lgpl.html
+ *
+ * JOAFIP is distributed in the hope that it will be useful, but
+ * 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.sf.joafip.heapfile.service;
+
+import net.sf.joafip.DoNotTransform;
+import net.sf.joafip.NotStorableClass;
+import net.sf.joafip.TestException;
+import net.sf.joafip.heapfile.record.entity.DataRecordIdentifier;
+
+/**
+ *
+ * @author luc peuvrier
+ *
+ */
+@NotStorableClass
+@DoNotTransform
+public abstract class AbstractTestHeapDataManagerImpl extends
+ AbstractTestHeapDataManagerRecord {
+
+ private static final String MUST_DELETE_1 = "must delete #1";
+
+ private static final String MUST_NOT_HAVE_DATA_RECORD = "must not have data record";
+
+ private static final String MUST_DELETE_0 = "must delete #0";
+
+ private static final String _0_FREE_RECORD_EXPECTED = "0 free record expected";
+
+ private static final String LAST_RECORD_MISMATCH = "last record mismatch";
+
+ private static final String MUST_HAVE_1_FREE_RECORD = "must have 1 free record";
+
+ private static final String MUST_NOT_HAVE_FREE_RECORD = "must not have free record";
+
+ private static final String MUST_HAVE_1_DATA_RECORD = "must have 1 data record";
+
+ private static final String MUST_HAVE_3_DATA_RECORD = "must have 3 data record";
+
+ public AbstractTestHeapDataManagerImpl() throws TestException {
+ super();
+ }
+
+ public AbstractTestHeapDataManagerImpl(final String name)
+ throws TestException {
+ super(name);
+ }
+
+ public void testEmpty() throws HeapException {
+ createHeap(true);
+ assertNull("reading must failed",
+ heapDataManager.readDataRecord(DataRecordIdentifier.ZERO));
+ checkIntegrity();
+ }
+
+ public void testFirstCreateClose() throws HeapException {// NOPMD
+ createHeap(true);
+ final int dataSize = 100;
+ createRecord(dataSize, 0);
+ closeHeap();
+ createHeap(false/* remove file */);
+ checkIntegrity();
+ firstCreatedReadAndCheck(dataSize);
+ }
+
+ public void testFirstCreateNoClose() throws HeapException {// NOPMD
+ createHeap(true);
+ final int dataSize = 100;
+ createRecord(dataSize, 0);
+ firstCreatedReadAndCheck(dataSize);
+ }
+
+ public void testDeleteClose() throws HeapException {// NOPMD
+ createHeap(true);
+ final int dataSize = 100;
+ createRecord(dataSize, 0);
+ checkIntegrity();
+ closeHeap();
+ createHeap(false/* remove file */);
+ final DataRecordIdentifier identifier = new DataRecordIdentifier(0);
+ assertTrue(MUST_DELETE_0, heapDataManager.deleteDataRecord(identifier));
+ closeHeap();
+ createHeap(false/* remove file */);
+ checkIntegrity();
+ }
+
+ public void testDeleteNoClose() throws HeapException {// NOPMD
+ createHeap(true);
+ final int dataSize = 100;
+ createRecord(dataSize, 0);
+ final DataRecordIdentifier identifier = new DataRecordIdentifier(0);
+ assertTrue(MUST_DELETE_0, heapDataManager.deleteDataRecord(identifier));
+ checkIntegrity();
+ }
+
+ /**
+ * @param dataSize
+ * @throws HeapException
+ *
+ */
+ private void firstCreatedReadAndCheck(final int dataSize)
+ throws HeapException {
+ final DataRecordIdentifier identifier = new DataRecordIdentifier(0);
+ checkDataRecord(dataSize, identifier);
+ checkIntegrity();
+ }
+
+ public void testAlloc() throws HeapException {
+ createHeap(true);
+ for (int index = 0; index < 10; index++) {
+ final DataRecordIdentifier identifier = heapDataManager
+ .getNewDataRecordIdentifier();
+ final byte[] data = new byte[1000]; // NOPMD
+ for (int dataIndex = 0; dataIndex < 1000; dataIndex++) {
+ data[dataIndex] = (byte) index;
+ }
+ heapDataManager.writeDataRecord(identifier, data);
+ logger.info("add #id=" + identifier);
+ logger.info("--------");
+ }
+ checkIntegrity();
+ closeHeap();
+ createHeap(false/* remove file */);
+ for (int identifier = 0; identifier < 10; identifier++) {
+ final DataRecordIdentifier dataRecordIdentifier = newDataRecordIdentifier(identifier);
+ final byte[] data = heapDataManager
+ .readDataRecord(dataRecordIdentifier);
+ assertNotNull("must exist data for identifier " + identifier, data);
+ for (int dataIndex = 0; dataIndex < 1000; dataIndex++) {
+ assertEquals("bad data value at " + dataIndex, data[dataIndex],
+ (byte) identifier);
+ }
+ }
+ }
+
+ /**
+ * realloc from only one free record keeping one free record
+ *
+ * @throws HeapException
+ */
+ public void testFreeReAlloc1() throws HeapException {
+ /*
+ * create record #0 of 10000 bytes, check data record and free record
+ */
+ createHeap(true);
+ int dataSize = 10000;
+ createRecord(dataSize, 0);
+ closeHeap();
+
+ createHeap(false/* remove file */);
+ assertEquals(MUST_HAVE_1_DATA_RECORD, 1,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_NOT_HAVE_FREE_RECORD, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ checkIntegrity();
+
+ /*
+ * delete record #0, check data record and free record
+ */
+ final DataRecordIdentifier identifier = new DataRecordIdentifier(0);
+ assertTrue(MUST_DELETE_0, heapDataManager.deleteDataRecord(identifier));
+ closeHeap();
+
+ createHeap(false/* remove file */);
+ assertEquals(MUST_NOT_HAVE_DATA_RECORD, 0,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_HAVE_1_FREE_RECORD, 1,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ checkIntegrity();
+
+ /*
+ * create record #1 of 5000 byte, check 1 data record and 1 free record
+ */
+ dataSize = 5000;
+ createRecord(dataSize, 1);
+ closeHeap();
+
+ createHeap(false/* remove file */);
+ checkIntegrity();
+ assertEquals(MUST_HAVE_1_DATA_RECORD, 1,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_HAVE_1_FREE_RECORD, 1,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ closeHeap();
+ }
+
+ /**
+ * realloc from only one free record keeping no more free record
+ *
+ * @throws HeapException
+ */
+ public void testFreeReAlloc2() throws HeapException {
+ createHeap(true);
+ int dataSize = 10000;
+ createRecord(dataSize, 0);
+ closeHeap();
+ createHeap(false/* remove file */);
+ assertEquals(MUST_HAVE_1_DATA_RECORD, 1,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_NOT_HAVE_FREE_RECORD, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ checkIntegrity();
+ final DataRecordIdentifier identifier = new DataRecordIdentifier(0);
+ assertTrue(MUST_DELETE_0, heapDataManager.deleteDataRecord(identifier));
+ closeHeap();
+ createHeap(false/* remove file */);
+ assertEquals(MUST_NOT_HAVE_DATA_RECORD, 0,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_HAVE_1_FREE_RECORD, 1,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ checkIntegrity();
+
+ dataSize = 9999;
+ createRecord(dataSize, 1);
+ closeHeap();
+ createHeap(false/* remove file */);
+ checkIntegrity();
+ assertEquals(MUST_HAVE_1_DATA_RECORD, 1,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_NOT_HAVE_FREE_RECORD, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ closeHeap();
+ }
+
+ /**
+ * realloc from only one free record keeping one free record
+ *
+ * @throws HeapException
+ */
+ public void testFreeReAlloc3() throws HeapException {
+ createHeap(true);
+ int dataSize = 10000;
+ createRecord(dataSize, 0);
+ createRecord(dataSize, 1);
+ createRecord(dataSize, 2);
+ closeHeap();
+ createHeap(false/* remove file */);
+ assertEquals(MUST_HAVE_3_DATA_RECORD, 3,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_NOT_HAVE_FREE_RECORD, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ checkIntegrity();
+ final DataRecordIdentifier identifier = new DataRecordIdentifier(1);
+ assertTrue(MUST_DELETE_1, heapDataManager.deleteDataRecord(identifier));
+ closeHeap();
+ createHeap(false/* remove file */);
+ assertEquals("must have 2 data record", 2,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_HAVE_1_FREE_RECORD, 1,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ checkIntegrity();
+
+ dataSize = 5000;
+ createRecord(dataSize, 3);
+ closeHeap();
+ createHeap(false/* remove file */);
+ checkIntegrity();
+ assertEquals(MUST_HAVE_3_DATA_RECORD, 3,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_HAVE_1_FREE_RECORD, 1,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ closeHeap();
+ }
+
+ /**
+ * realloc from only one free record keeping no more free record
+ *
+ * @throws HeapException
+ */
+ public void testFreeReAlloc4() throws HeapException {
+ createHeap(true);
+ int dataSize = 10000;
+ createRecord(dataSize, 0);
+ assertEquals("1 data record expected", 1,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(_0_FREE_RECORD_EXPECTED, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ createRecord(dataSize, 1);
+ assertEquals("2 data record expected", 2,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(_0_FREE_RECORD_EXPECTED, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ createRecord(dataSize, 2);
+ assertEquals("3 data record expected", 3,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(_0_FREE_RECORD_EXPECTED, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ closeHeap();
+ createHeap(false/* remove file */);
+ assertEquals(MUST_HAVE_3_DATA_RECORD, 3,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_NOT_HAVE_FREE_RECORD, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ checkIntegrity();
+ final DataRecordIdentifier identifier = new DataRecordIdentifier(1);
+ assertTrue(MUST_DELETE_1, heapDataManager.deleteDataRecord(identifier));
+ closeHeap();
+ createHeap(false/* remove file */);
+ assertEquals("must have 2 data record", 2,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_HAVE_1_FREE_RECORD, 1,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ checkIntegrity();
+
+ dataSize = 9999;
+ createRecord(dataSize, 3);
+ assertEquals("3 data record expected", 3,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(_0_FREE_RECORD_EXPECTED, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+
+ closeHeap();
+ createHeap(false/* remove file */);
+ checkIntegrity();
+ assertEquals(MUST_HAVE_3_DATA_RECORD, 3,
+ heapDataManager.getNumberOfDataRecord());
+ if (manageFreeRecord()) {
+ assertEquals(MUST_NOT_HAVE_FREE_RECORD, 0,
+ heapDataManager.getNumberOfFreeRecord());
+ }
+ closeHeap();
+ }
+
+ public void testModification() throws HeapException {
+ createHeap(true);
+ byte[] data = createRecord(20, 0);
+ assertNotNull(DATA_MUST_BE_DEFINED, data);
+ for (int index = 0; index < 20; index++) {
+ data[index] = (byte) index;
+ }
+ checkIntegrity();
+ closeHeap();
+ createHeap(false/* remove file */);
+ final DataRecordIdentifier identifier = new DataRecordIdentifier(0);
+ data = heapDataManager.readDataRecord(identifier);
+ for (int index = 0; index < 20; index++) {
+ assertEquals("bad value", data[index], index);
+ }
+ for (int index = 0; index < 20; index++) {
+ data[index] = (byte) (10 + index);
+ }
+ heapDataManager.writeDataRecord(identifier, data);
+ closeHeap();
+ createHeap(false/* remove file */);
+ data = heapDataManager.readDataRecord(identifier);
+ for (int index = 0; index < 20; index++) {
+ assertEquals("bad value", data[index], 10 + index);
+ }
+ }
+
+ public void testNoDataWrite() throws HeapException {
+ createHeap(true);
+ final DataRecordIdentifier identifier = heapDataManager
+ .getNewDataRecordIdentifier();
+ byte[] data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+ final DataRecordIdentifier identifier0 = new DataRecordIdentifier(0);
+ assertEquals("not expected identifier", identifier0, identifier);
+ closeHeap();
+ createHeap(true/* remove file */);
+ data = heapDataManager.readDataRecord(identifier0);
+ assertNull("must failed since no data wrote", data);
+ }
+
+ public void testCreateDeleteReCreate() throws HeapException {
+ createHeap(true);
+ DataRecordIdentifier identifier = heapDataManager
+ .getNewDataRecordIdentifier();
+ byte[] data = new byte[10];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ DataRecordIdentifier expectedIdentifier = new DataRecordIdentifier(0);
+ assertEquals("identifier must be 0", expectedIdentifier, identifier);
+ assertTrue("must have data record #0",
+ heapDataManager.hasDataRecord(identifier));
+
+ assertTrue(MUST_DELETE_0, heapDataManager.deleteDataRecord(identifier));
+ assertFalse("must not have data record #0",
+ heapDataManager.hasDataRecord(identifier));
+
+ identifier = heapDataManager.getNewDataRecordIdentifier();
+ data = new byte[10];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ expectedIdentifier = new DataRecordIdentifier(1);
+ assertEquals("identifier must be 1", expectedIdentifier, identifier);
+ assertTrue("must have data record #0",
+ heapDataManager.hasDataRecord(identifier));
+ heapDataManager.flush();
+ }
+
+ public void testRecordFreeing1() throws HeapException {
+ createHeap(true);
+ /*
+ * create record #0
+ */
+ DataRecordIdentifier identifier = heapDataManager
+ .getNewDataRecordIdentifier();
+ byte[] data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ final DataRecordIdentifier expectedIdentifier0 = new DataRecordIdentifier(
+ 0);
+ assertEquals("must create record #0", expectedIdentifier0, identifier);
+
+ /*
+ * create record #1
+ */
+ identifier = heapDataManager.getNewDataRecordIdentifier();
+ data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ final DataRecordIdentifier expectedIdentifier1 = new DataRecordIdentifier(
+ 1);
+ assertEquals("must create record #1", expectedIdentifier1, identifier);
+
+ /*
+ * create record #2
+ */
+ identifier = heapDataManager.getNewDataRecordIdentifier();
+ data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ final DataRecordIdentifier expectedIdentifier2 = new DataRecordIdentifier(
+ 2);
+ assertEquals("must create record #2", expectedIdentifier2, identifier);
+
+ /*
+ * delete #0
+ */
+ identifier = new DataRecordIdentifier(0);
+ assertTrue(MUST_DELETE_0, heapDataManager.deleteDataRecord(identifier));
+ heapDataManager.flush();
+ final long record2PositionInFile = heapDataManager
+ .getRecordPositionInfile(expectedIdentifier2);
+
+ long lastRecordPositionInFile = heapDataManager
+ .getLastRecordPositionInFile();
+ assertEquals(LAST_RECORD_MISMATCH, record2PositionInFile,
+ lastRecordPositionInFile);
+
+ /*
+ * delete #1
+ */
+ identifier = new DataRecordIdentifier(1);
+ assertTrue(MUST_DELETE_1, heapDataManager.deleteDataRecord(identifier));
+ heapDataManager.flush();
+ lastRecordPositionInFile = heapDataManager
+ .getLastRecordPositionInFile();
+ assertEquals(LAST_RECORD_MISMATCH, lastRecordPositionInFile,
+ record2PositionInFile);
+ }
+
+ public void testRecordFreeing2() throws HeapException {
+ createHeap(true);
+ /*
+ * create record #0
+ */
+ DataRecordIdentifier identifier = heapDataManager
+ .getNewDataRecordIdentifier();
+ byte[] data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ final DataRecordIdentifier expectedIdentifier = new DataRecordIdentifier(
+ 0);
+ assertEquals("must create record #0", expectedIdentifier, identifier);
+
+ /*
+ * create record #1
+ */
+ identifier = heapDataManager.getNewDataRecordIdentifier();
+ data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ final DataRecordIdentifier expectedIdentifier1 = new DataRecordIdentifier(
+ 1);
+ assertEquals("must create record #1", expectedIdentifier1, identifier);
+ heapDataManager.flush();
+ final long record1PositionInFile = heapDataManager
+ .getRecordPositionInfile(expectedIdentifier1);
+
+ /*
+ * create record #2
+ */
+ identifier = heapDataManager.getNewDataRecordIdentifier();
+ data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ final DataRecordIdentifier expectedIdentifier2 = new DataRecordIdentifier(
+ 2);
+ assertEquals("must create record #2", expectedIdentifier2, identifier);
+ heapDataManager.flush();
+ final long record2PositionInFile = heapDataManager
+ .getRecordPositionInfile(expectedIdentifier2);
+
+ /*
+ * delete #2
+ */
+ identifier = new DataRecordIdentifier(2);
+ assertTrue("must delete #2",
+ heapDataManager.deleteDataRecord(identifier));
+ heapDataManager.flush();
+ long lastRecordPositionInFile = heapDataManager
+ .getLastRecordPositionInFile();
+ assertEquals(LAST_RECORD_MISMATCH, record2PositionInFile,
+ lastRecordPositionInFile);
+
+ /*
+ * delete #1
+ */
+ identifier = new DataRecordIdentifier(1);
+ assertTrue(MUST_DELETE_1, heapDataManager.deleteDataRecord(identifier));
+ heapDataManager.flush();
+ lastRecordPositionInFile = heapDataManager
+ .getLastRecordPositionInFile();
+ if (manageFreeRecord()) {
+ assertEquals(LAST_RECORD_MISMATCH, record1PositionInFile,
+ lastRecordPositionInFile);
+ }
+ }
+
+ public void testRecordFreeing3() throws HeapException {
+ createHeap(true);
+ DataRecordIdentifier identifier = heapDataManager
+ .getNewDataRecordIdentifier();
+ byte[] data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ DataRecordIdentifier expectedIdentifier = new DataRecordIdentifier(0);
+ assertEquals("must create record #0", expectedIdentifier, identifier);
+
+ identifier = heapDataManager.getNewDataRecordIdentifier();
+ data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ expectedIdentifier = new DataRecordIdentifier(1);
+ assertEquals("must create record #1", expectedIdentifier, identifier);
+
+ identifier = heapDataManager.getNewDataRecordIdentifier();
+ data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+
+ expectedIdentifier = new DataRecordIdentifier(2);
+ assertEquals("must create record #2", expectedIdentifier, identifier);
+
+ identifier = new DataRecordIdentifier(0);
+ assertTrue(MUST_DELETE_0, heapDataManager.deleteDataRecord(identifier));
+ identifier = new DataRecordIdentifier(2);
+ assertTrue("must delete #2",
+ heapDataManager.deleteDataRecord(identifier));
+ heapDataManager.flush();
+ identifier = new DataRecordIdentifier(1);
+ assertTrue(MUST_DELETE_1, heapDataManager.deleteDataRecord(identifier));
+ }
+
+ public void testRemoveFirst() throws HeapException {
+ createHeap(true);
+ assertNull(MUST_NOT_HAVE_DATA_RECORD,
+ heapDataManager.removeFirstDataRecord());
+ DataRecordIdentifier identifier = heapDataManager
+ .getNewDataRecordIdentifier();
+ final byte[] data = new byte[100];
+ heapDataManager.writeDataRecord(identifier, data);
+ identifier = heapDataManager.getNewDataRecordIdentifier();
+ heapDataManager.writeDataRecord(identifier, data);
+ heapDataManager.flush();
+ identifier = heapDataManager.removeFirstDataRecord();
+ assertNotNull("must deleted first data record", identifier);
+ assertEquals(0L, identifier.value);
+ identifier = heapDataManager.removeFirstDataRecord();
+ assertNotNull("must deleted first data record", identifier);
+ assertEquals(1L, identifier.value);
+ assertNull(MUST_NOT_HAVE_DATA_RECORD,
+ heapDataManager.removeFirstDataRecord());
+ }
+}
Added: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/BlockDataManager.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/BlockDataManager.java (rev 0)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/BlockDataManager.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -0,0 +1,493 @@
+/*
+ * Copyright 2011 Luc Peuvrier
+ *
+ * This file is a part of JOAFIP.
+ *
+ * JOAFIP is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE
+ * Licensed under the LGPL License, Version 3, 29 June 2007 (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.gnu.org/licenses/lgpl.html
+ *
+ * JOAFIP is distributed in the hope that it will be useful, but
+ * 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.sf.joafip.heapfile.service;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import net.sf.joafip.NotStorableClass;
+import net.sf.joafip.file.service.FileIOException;
+import net.sf.joafip.file.service.IRandomAccessFile;
+import net.sf.joafip.file.service.RandomAccessFileDirectNio;
+import net.sf.joafip.file.service.RandomAccessFileReadWriteCache;
+import net.sf.joafip.heapfile.entity.BlockDataManagerHeader;
+import net.sf.joafip.heapfile.entity.DataBlock;
+import net.sf.joafip.heapfile.record.entity.DataRecordIdentifier;
+
+/**
+ *
+ * @author luc peuvrier
+ *
+ */
+@NotStorableClass
+public class BlockDataManager extends AbstractHeapDataManager {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7880032946404411395L;
+
+ private static final int FIRST_BLOCK_LENGTH = 1024;
+
+ private final IRandomAccessFile randomAccessFile;
+
+ private final BlockDataManagerHeader header = new BlockDataManagerHeader();
+
+ private final Map<Long, DataBlock> cacheMap = new TreeMap<Long, DataBlock>();
+
+ public BlockDataManager(final String filePath, final int blockLength)
+ throws HeapException {
+ super();
+ final File file = new File(filePath);
+ randomAccessFile = new RandomAccessFileDirectNio(file, 0, 0);
+ // randomAccessFile = new RandomAccessFileDirect(file, 0, 0);
+ header.setBlockLength(blockLength);
+ }
+
+ public BlockDataManager(final int pageSize, final int maxPage,
+ final int blockLength) throws HeapException {
+ super();
+ final File file = new File("runtime/data");
+ final IRandomAccessFile drandomAccessFile = new RandomAccessFileDirectNio(
+ file, 0, 0);
+ randomAccessFile = new RandomAccessFileReadWriteCache(
+ drandomAccessFile, pageSize, maxPage, true);
+ header.setBlockLength(blockLength);
+ }
+
+ @Override
+ protected void removeFiles() throws HeapException {
+ try {
+ randomAccessFile.deleteIfExists();
+ } catch (FileIOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ @Override
+ protected void startServiceImpl(final boolean removeFiles)
+ throws HeapException {
+ try {
+ randomAccessFile.open();
+ randomAccessFile.seek(0);
+ final byte[] block = new byte[FIRST_BLOCK_LENGTH];
+ if (removeFiles) {
+ randomAccessFile.write(block);
+ header.setNextIdentifier(new DataRecordIdentifier());
+ header.setNumberOfDataRecord(0);
+ } else {
+ if (randomAccessFile.read(block) == FIRST_BLOCK_LENGTH) {
+ final int length = (((int) block[0]) & 0xff) << 8
+ | (((int) block[1]) & 0xff);
+ final byte[] data = new byte[length];
+ System.arraycopy(block, 2, data, 0, length);
+ header.set(data);
+ } else {
+ randomAccessFile.write(block);
+ header.setNextIdentifier(new DataRecordIdentifier());
+ header.setNumberOfDataRecord(0);
+ }
+ }
+ } catch (FileIOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ @Override
+ protected void stopServiceImpl() throws HeapException {
+ try {
+ writeHeader();
+ randomAccessFile.close();
+ } catch (FileIOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ private void writeHeader() throws HeapException, FileIOException {
+ final byte[] data = header.get();
+ final int length = data.length;
+ final byte[] block = new byte[(int) FIRST_BLOCK_LENGTH];
+ block[0] = (byte) (length >> 8);
+ block[1] = (byte) length;
+ System.arraycopy(data, 0, block, 2, length);
+ randomAccessFile.seek(0);
+ randomAccessFile.write(block);
+ }
+
+ @Override
+ protected void clearImpl() throws HeapException {
+ removeFiles();
+ }
+
+ @Override
+ protected void flushImp() throws HeapException {
+ try {
+ for (Map.Entry<Long, DataBlock> entry : cacheMap.entrySet()) {
+ final long position = entry.getKey();
+ final DataBlock dataBlock = entry.getValue();
+ if (dataBlock.isToWrite()) {
+ randomAccessFile.seek(position);
+ randomAccessFile.write(dataBlock.getData());
+ }
+ }
+ writeHeader();
+ randomAccessFile.flush();
+ cacheMap.clear();
+ } catch (FileIOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ @Override
+ protected void clearStandbyModificationImpl() throws HeapException {
+ cacheMap.clear();
+ }
+
+ @Override
+ protected DataRecordIdentifier getNextFreeDataRecordIdentifierImpl()
+ throws HeapException {
+ return header.getNextIdentifier();
+ }
+
+ @Override
+ protected void setNextFreeDataRecordIdentifierImpl(
+ final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ header.setNextIdentifier(dataRecordIdentifier);
+ }
+
+ @Override
+ protected DataRecordIdentifier getNewDataRecordIdentifierImpl()
+ throws HeapException {
+ final DataRecordIdentifier result = header.getNextIdentifier();
+ header.setNextIdentifier(new DataRecordIdentifier(result));
+ return result;
+ }
+
+ @Override
+ protected boolean deleteDataRecordImpl(
+ final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ try {
+ final long position = getRecordPositionInfile(dataRecordIdentifier);
+ final boolean deleted;
+ final byte[] lengthData = new byte[2];
+ final int read = read(position, 0, lengthData,true);
+ if (read == 2) {
+ final int length = (((int) lengthData[0]) & 0xff) << 8
+ | (((int) lengthData[1]) & 0xff);
+ if (length == 0) {
+ deleted = false;
+ } else {
+ header.decrementNumberOfDataRecord();
+ deleted = true;
+ lengthData[0] = (byte) 0;
+ lengthData[1] = (byte) 0;
+ write(position, 0, lengthData);
+ }
+ } else {
+ deleted = false;
+ }
+ return deleted;
+ } catch (FileIOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ @Override
+ protected byte[] readDataRecordImpl(
+ final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ try {
+ final long position = getRecordPositionInfile(dataRecordIdentifier);
+ byte[] data = new byte[2];
+ final int read = read(position, 0, data,true);
+ if (read == 2) {
+ final int length = (((int) data[0]) & 0xff) << 8
+ | (((int) data[1]) & 0xff);
+
+ if (length == 0) {
+ data = null;// NOPMD
+ } else {
+ data = new byte[length];
+ read(position, 2, data,true);
+ }
+ } else {
+ data = null;// NOPMD
+ }
+ return data;
+ } catch (FileIOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ @Override
+ protected boolean writeDataRecordImpl(
+ final DataRecordIdentifier dataRecordIdentifier, final byte[] data)
+ throws HeapException {
+ if (data.length == 0) {
+ throw new HeapException("no data");
+ }
+ if (data.length > header.getBlockLength() - 2) {
+ throw new HeapException("too big data: " + data.length
+ + " for block of " + header.getBlockLength());
+ }
+ try {
+ final long position = getRecordPositionInfile(dataRecordIdentifier);
+ final boolean created;
+ final byte[] lengthData = new byte[2];
+ int previousLength = -1;
+ final int read = read(position, 0, lengthData,true);
+ if (read == 2) {
+ previousLength = (((int) lengthData[0]) & 0xff) << 8
+ | (((int) lengthData[1]) & 0xff);
+ created = previousLength == 0;
+ } else {
+ created = true;
+ }
+ if (created) {
+ header.incrementNumberOfDataRecord();
+ }
+ final int length = data.length;
+ lengthData[0] = (byte) (length >> 8);
+ lengthData[1] = (byte) length;
+ write(position, 0, lengthData);
+ write(position, 2, data);
+ return created;
+ } catch (FileIOException exception) {
+ throw new HeapException("for data record #" + dataRecordIdentifier,
+ exception);
+ }
+ }
+
+ @Override
+ protected boolean hasDataRecordImpl(
+ final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ try {
+ final long position = getRecordPositionInfile(dataRecordIdentifier);
+ final boolean hasDatarecord;
+ final byte[] lengthData = new byte[2];
+ final int read = read(position, 0, lengthData,true);
+ if (read == 2) {
+ final int length = (((int) lengthData[0]) & 0xff) << 8
+ | (((int) lengthData[1]) & 0xff);
+ hasDatarecord = length != 0;
+ } else {
+ hasDatarecord = false;
+ }
+ return hasDatarecord;
+ } catch (FileIOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ @Override
+ public long getRecordPositionInfile(
+ final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ final long value = dataRecordIdentifier.value;
+ return getRecordPositionInfile(value);
+ }
+
+ private long getRecordPositionInfile(final long value) {
+ return value * header.getBlockLength() + FIRST_BLOCK_LENGTH;
+ }
+
+ @Override
+ public long getLastRecordPositionInFile() throws HeapException {
+ return getRecordPositionInfile((header.getDataLength() - 1 - FIRST_BLOCK_LENGTH)
+ / header.getBlockLength());
+ }
+
+ @Override
+ protected int getNumberOfDataRecordImpl() throws HeapException {
+ return header.getNumberOfDataRecord();
+ }
+
+ @Override
+ protected DataRecordIdentifier removeFirstDataRecordImpl()
+ throws HeapException {
+ try {
+ boolean found = false;
+ final long firstRecordPositionInfile = getRecordPositionInfile(0);
+ long position = firstRecordPositionInfile;
+ final byte[] lengthData = new byte[2];
+ do {
+ final int read = read(position, 0, lengthData,false);
+ if (read == 2) {
+ final int length = (((int) lengthData[0]) & 0xff) << 8
+ | (((int) lengthData[1]) & 0xff);
+ if (length == 0) {
+ position += header.getBlockLength();
+ } else {
+ found = true;
+ }
+ } else {
+ position = Long.MAX_VALUE;
+ }
+ } while (!found && position < header.getDataLength());
+ DataRecordIdentifier result;
+ if (found) {
+ lengthData[0] = 0;
+ lengthData[1] = 0;
+ write(position, 0, lengthData);
+ result = new DataRecordIdentifier(
+ (position - firstRecordPositionInfile)
+ / header.getBlockLength());
+ } else {
+ result = null;// NOPMD
+ }
+ return result;
+ } catch (FileIOException exception) {
+ throw new HeapException(exception);
+ }
+ }
+
+ @Override
+ protected int getNumberOfFreeRecordImpl() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ protected long heapSizeImpl() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ protected long freeSizeImpl() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ protected long usedSizeImpl() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ protected Set<DataRecordIdentifier> getDataRecordIdentifierSetImpl()
+ throws HeapException {
+ // no implementation
+ return null;
+ }
+
+ @Override
+ protected Iterator<DataRecordIdentifier> dataRecordIteratorImpl() {
+ // no implementation
+ return null;
+ }
+
+ @Override
+ protected void closeHeapManagerAfterException() {
+ // no implementation
+ }
+
+ @Override
+ public boolean isDataLost() {
+ return false;
+ }
+
+ @Override
+ public String getStorageFileName() throws HeapException {
+ return randomAccessFile.getFile().getAbsolutePath();
+ }
+
+ @Override
+ public void backup(final long identifier, final int maxBackup)
+ throws HeapException {
+ throw new HeapException("not implemented");
+ }
+
+ @Override
+ public String getBackupFileName() throws HeapException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getChangeFileName() throws HeapException {
+ return null;
+ }
+
+ private int read(final long position, final int offset, final byte[] data,
+ final boolean addToCache) throws FileIOException {
+ DataBlock dataBlock = cacheMap.get(position);
+ if (dataBlock == null) {
+ dataBlock = readInFile(position, addToCache);
+ }
+ final int result;
+ if (dataBlock == null) {
+ result = 0;
+ } else {
+ result = data.length;
+ final byte[] recordData = dataBlock.getData();
+ System.arraycopy(recordData, offset, data, 0, result);
+ }
+ return result;
+ }
+
+ private DataBlock readInFile(final long position, final boolean addToCache)
+ throws FileIOException {
+ final DataBlock dataBlock;
+ randomAccessFile.seek(position);
+ final int blockLength = header.getBlockLength();
+ final byte[] recordData = new byte[blockLength];
+ final int read = randomAccessFile.read(recordData);
+ if (read == blockLength) {
+ dataBlock = new DataBlock(position, false, recordData);
+ if (addToCache) {
+ cacheMap.put(position, dataBlock);
+ }
+ } else {
+ dataBlock = null;
+ }
+ return dataBlock;
+ }
+
+ private void write(final long position, final int offset, final byte[] data)
+ throws FileIOException {
+ DataBlock dataBlock = cacheMap.get(position);
+ if (dataBlock == null) {
+ dataBlock = readInFile(position,true);
+ if (dataBlock == null) {
+ final byte[] recordData = new byte[header.getBlockLength()];
+ dataBlock = new DataBlock(position, true, recordData);
+ cacheMap.put(position, dataBlock);
+ }
+ } else {
+ dataBlock.setToWrite(true);
+ }
+ System.arraycopy(data, 0, dataBlock.getData(), offset, data.length);
+ final long length = position + header.getBlockLength();
+ if (length > header.getDataLength()) {
+ header.setDataLength(length);
+ }
+ }
+}
Added: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/DualWrapDataManager.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/DualWrapDataManager.java (rev 0)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/DualWrapDataManager.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2011 Luc Peuvrier
+ *
+ * This file is a part of JOAFIP.
+ *
+ * JOAFIP is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License.
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE
+ * Licensed under the LGPL License, Version 3, 29 June 2007 (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.gnu.org/licenses/lgpl.html
+ *
+ * JOAFIP is distributed in the hope that it will be useful, but
+ * 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.sf.joafip.heapfile.service;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.Set;
+
+import net.sf.joafip.heapfile.record.entity.DataRecordIdentifier;
+
+/**
+ *
+ * @author luc peuvrier
+ *
+ */
+public class DualWrapDataManager implements IHeapDataManager {
+
+ private final IHeapDataManager firstDataManager;
+
+ private final IHeapDataManager secondDataManager;
+
+ public DualWrapDataManager(final IHeapDataManager firstDataManager,
+ final IHeapDataManager secondDataManager) {
+ super();
+ this.firstDataManager = firstDataManager;
+ this.secondDataManager = secondDataManager;
+ }
+
+ @Override
+ public boolean isDataLost() {
+ // no implementation
+ return false;
+ }
+
+ @Override
+ public void startService(final boolean removeFiles) throws HeapException {
+ firstDataManager.startService(removeFiles);
+ secondDataManager.startService(removeFiles);
+ }
+
+ @Override
+ public void stopService() throws HeapException {
+ firstDataManager.stopService();
+ secondDataManager.stopService();
+ }
+
+ @Override
+ public boolean isServiceStarted() {
+ final boolean started1 = firstDataManager.isServiceStarted();
+ final boolean started2 = secondDataManager.isServiceStarted();
+ if (started1 != started2) {
+ throw new HeapRuntimeException("started stated missmatch "
+ + started1 + " " + started2);
+ }
+ return started1;
+ }
+
+ @Override
+ public void clear() throws HeapException {
+ firstDataManager.clear();
+ secondDataManager.clear();
+ }
+
+ @Override
+ public DataRecordIdentifier getNextFreeDataRecordIdentifier()
+ throws HeapException {
+ final DataRecordIdentifier next1 = firstDataManager
+ .getNextFreeDataRecordIdentifier();
+ final DataRecordIdentifier next2 = secondDataManager
+ .getNextFreeDataRecordIdentifier();
+ if (next1.value != next2.value) {
+ throw new HeapException("new data record identifier missmatch "
+ + next1.value + " " + next2.value);
+ }
+ return next1;
+ }
+
+ @Override
+ public void setNextFreeDataRecordIdentifier(
+ final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ firstDataManager.setNextFreeDataRecordIdentifier(dataRecordIdentifier);
+ secondDataManager.setNextFreeDataRecordIdentifier(dataRecordIdentifier);
+ }
+
+ @Override
+ public DataRecordIdentifier getNewDataRecordIdentifier()
+ throws HeapException {
+ final DataRecordIdentifier new1 = firstDataManager
+ .getNewDataRecordIdentifier();
+ final DataRecordIdentifier new2 = secondDataManager
+ .getNewDataRecordIdentifier();
+ if (new1.value != new2.value) {
+ throw new HeapException("new data record identifier missmatch "
+ + new1.value + " " + new2.value);
+ }
+ return new1;
+ }
+
+ @Override
+ public boolean hasDataRecord(final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ final boolean has1 = firstDataManager
+ .hasDataRecord(dataRecordIdentifier);
+ final boolean has2 = secondDataManager
+ .hasDataRecord(dataRecordIdentifier);
+ if (has1 != has2) {
+ throw new HeapException("has data record missmatch " + has1 + " "
+ + has2);
+ }
+ return has1;
+ }
+
+ @Override
+ public byte[] readDataRecord(final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ final byte[] data1 = firstDataManager
+ .readDataRecord(dataRecordIdentifier);
+ final byte[] data2 = secondDataManager
+ .readDataRecord(dataRecordIdentifier);
+ if (!Arrays.equals(data1, data2)) {
+ throw new HeapException("data differs");
+ }
+ return data1;
+ }
+
+ @Override
+ public boolean writeDataRecord(
+ final DataRecordIdentifier dataRecordIdentifier, final byte[] data)
+ throws HeapException {
+ final boolean created1 = firstDataManager.writeDataRecord(
+ dataRecordIdentifier, data);
+ final boolean created2 = secondDataManager.writeDataRecord(
+ dataRecordIdentifier, data);
+ if (created1 != created2) {
+ throw new HeapException("created state missmatch " + created1 + " "
+ + created2 + " for " + dataRecordIdentifier);
+ }
+ return created1;
+ }
+
+ @Override
+ public boolean deleteDataRecord(
+ final DataRecordIdentifier dataRecordIdentifier)
+ throws HeapException {
+ final boolean deleted1 = firstDataManager
+ .deleteDataRecord(dataRecordIdentifier);
+ final boolean deleted2 = secondDataManager
+ .deleteDataRecord(dataRecordIdentifier);
+ if (deleted1 != deleted2) {
+ throw new HeapException("deleted state missmatch " + deleted1 + " "
+ + deleted2);
+ }
+ return deleted1;
+ }
+
+ @Override
+ public DataRecordIdentifier removeFirstDataRecord() throws HeapException {
+ final DataRecordIdentifier dr1 = firstDataManager
+ .removeFirstDataRecord();
+ final DataRecordIdentifier dr2 = secondDataManager
+ .removeFirstDataRecord();
+ if (dr1.value != dr2.value) {
+ throw new HeapException("data record mismatch " + dr1.value + " "
+ + dr2.value);
+ }
+ return dr1;
+ }
+
+ @Override
+ public void flush() throws HeapException {
+ firstDataManager.flush();
+ secondDataManager.flush();
+ }
+
+ @Override
+ public void clearStandbyModification() throws HeapException {
+ firstDataManager.clearStandbyModification();
+ secondDataManager.clearStandbyModification();
+ }
+
+ @Override
+ public int getNumberOfDataRecord() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ public int getNumberOfFreeRecord() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ public long heapSize() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ public long freeSize() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ public long usedSize() throws HeapException {
+ // no implementation
+ return 0;
+ }
+
+ @Override
+ public void backup(final long identifier, final int maxBackup)
+ throws HeapException {
+ // no implementation
+ }
+
+ @Override
+ public String getStorageFileName() throws HeapException {
+ // no implementation
+ return null;
+ }
+
+ @Override
+ public String getBackupFileName() throws HeapException {
+ // no implementation
+ return null;
+ }
+
+ @Override
+ public String getChangeFileName() throws HeapException {
+ // no implementation
+ return null;
+ }
+
+ @Override
+ public Set<DataRecordIdentifier> getDataRecordIdentifierSet()
+ throws HeapException {
+ // no implementation
+ return null;
+ }
+
+ @Override
+ public Iterator<DataRecordIdentifier> dataRecordIterator()
+ throws HeapException {
+ // no implementation
+ return null;
+ }
+
+ @Override
+ public long getRecordPositionInfile(final DataRecordIdentifier identifier)
+ throws HeapException {
+ throw new HeapException("unsupported");
+ }
+
+ @Override
+ public long getLastRecordPositionInFile() throws HeapException {
+ throw new HeapException("unsupported");
+ }
+}
Modified: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapFileCheckerDataManager.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapFileCheckerDataManager.java 2011-11-12 16:49:48 UTC (rev 2963)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapFileCheckerDataManager.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -248,4 +248,15 @@
throws HeapException {
return heapFileDataManager.dataRecordIterator();
}
+
+ @Override
+ public long getRecordPositionInfile(final DataRecordIdentifier identifier)
+ throws HeapException {
+ throw new HeapException("unsupported");
+ }
+
+ @Override
+ public long getLastRecordPositionInFile() throws HeapException {
+ throw new HeapException("unsupported");
+ }
}
Modified: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapMemoryDataManagerMock.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapMemoryDataManagerMock.java 2011-11-12 16:49:48 UTC (rev 2963)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapMemoryDataManagerMock.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -291,4 +291,15 @@
public Iterator<DataRecordIdentifier> dataRecordIteratorImpl() {
return getDataRecordIdentifierSetImpl().iterator();
}
+
+ @Override
+ public long getRecordPositionInfile(final DataRecordIdentifier identifier)
+ throws HeapException {
+ throw new HeapException(UNSUPPORTED);
+ }
+
+ @Override
+ public long getLastRecordPositionInFile() throws HeapException {
+ throw new HeapException(UNSUPPORTED);
+ }
}
\ No newline at end of file
Modified: trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapMultiFileDataManager.java
===================================================================
--- trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapMultiFileDataManager.java 2011-11-12 16:49:48 UTC (rev 2963)
+++ trunk/joafip-heapfile/src/test/java/net/sf/joafip/heapfile/service/HeapMultiFileDataManager.java 2011-11-12 16:53:35 UTC (rev 2964)
@@ -462,4 +462,15 @@
public Iterator<DataRecordIdentifier> dataRecordIteratorImpl() {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public long getR...
[truncated message content] |