[Home] Restricted access for guests. The link to Java source code is disabled
Java source code of 'jhplot.io.db.RecordsFile'
/**
* Copyright (C) DataMelt project. The jHPLot package by S.Chekanov and Work.ORG
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, see .
*
* Additional permission under GNU GPL version 3 section 7:
* If you have received this program as a library with written permission from the DataMelt team,
* you can link or combine this library with your non-GPL project to convey the resulting work.
* In this case, this library should be considered as released under the terms of
* GNU Lesser public license (see ),
* provided you include this license notice and a URL through which recipients can access the
* Corresponding Source.
**/
package jhplot.io.db;
import java.io.*;
import java.util.*;
public class RecordsFile extends BaseRecordsFile {
/**
* Hashtable which holds the in-memory index. For efficiency, the entire index
* is cached in memory. The hashtable maps a key of type String to a RecordHeader.
*/
protected Hashtable memIndex;
/**
* Creates a new database file. The initialSize parameter determines the
* amount of space which is allocated for the index. The index can grow
* dynamically, but the parameter is provide to increase
* efficiency.
*/
public RecordsFile(String dbPath, int initialSize) throws IOException, RecordsFileException {
super(dbPath, initialSize);
memIndex = new Hashtable(initialSize);
}
/**
* Opens an existing database and initializes the in-memory index.
*/
public RecordsFile(String dbPath, String accessFlags) throws IOException, RecordsFileException {
super(dbPath, accessFlags);
int numRecords = readNumRecordsHeader();
memIndex = new Hashtable(numRecords);
for (int i = 0; i < numRecords; i++) {
String key = readKeyFromIndex(i);
RecordHeader header = readRecordHeaderFromIndex(i);
header.setIndexPosition(i);
memIndex.put(key, header);
}
}
/**
* Returns an enumeration of all the keys in the database.
*/
public synchronized Enumeration enumerateKeys() {
return memIndex.keys();
}
/**
* Returns the current number of records in the database.
*/
public synchronized int getNumRecords() {
return memIndex.size();
}
/**
* Checks if there is a record belonging to the given key.
*/
public synchronized boolean recordExists(String key) {
return memIndex.containsKey(key);
}
/**
* Maps a key to a record header by looking it up in the in-memory index.
*/
protected RecordHeader keyToRecordHeader(String key) throws RecordsFileException {
RecordHeader h = (RecordHeader)memIndex.get(key);
if (h==null) {
throw new RecordsFileException("Key not found: " + key);
}
return h;
}
/**
* This method searches the file for free space and then returns a RecordHeader
* which uses the space. (O(n) memory accesses)
*/
protected RecordHeader allocateRecord(String key, int dataLength) throws RecordsFileException, IOException {
// search for empty space
RecordHeader newRecord = null;
Enumeration e = memIndex.elements();
while (e.hasMoreElements()) {
RecordHeader next = (RecordHeader)e.nextElement();
int free = next.getFreeSpace();
if (dataLength <= next.getFreeSpace()) {
newRecord = next.split();
writeRecordHeaderToIndex(next);
break;
}
}
if (newRecord == null) {
// append record to end of file - grows file to allocate space
long fp = getFileLength();
setFileLength(fp + dataLength);
newRecord = new RecordHeader(fp, dataLength);
}
return newRecord;
}
/**
* Returns the record to which the target file pointer belongs - meaning the specified location
* in the file is part of the record data of the RecordHeader which is returned. Returns null if
* the location is not part of a record. (O(n) mem accesses)
*/
protected RecordHeader getRecordAt(long targetFp) throws RecordsFileException {
Enumeration e = memIndex.elements();
while (e.hasMoreElements()) {
RecordHeader next = (RecordHeader) e.nextElement();
if (targetFp >= next.dataPointer &&
targetFp < next.dataPointer + (long)next.dataCapacity) {
return next;
}
}
return null;
}
/**
* Closes the database.
*/
public synchronized void close() throws IOException, RecordsFileException {
try {
super.close();
} finally {
memIndex.clear();
memIndex = null;
}
}
/**
* Adds the new record to the in-memory index and calls the super class add
* the index entry to the file.
*/
protected void addEntryToIndex(String key, RecordHeader newRecord, int currentNumRecords) throws IOException, RecordsFileException {
super.addEntryToIndex(key, newRecord, currentNumRecords);
memIndex.put(key, newRecord);
}
/**
* Removes the record from the index. Replaces the target with the entry at the
* end of the index.
*/
protected void deleteEntryFromIndex(String key, RecordHeader header, int currentNumRecords) throws IOException, RecordsFileException {
super.deleteEntryFromIndex(key, header, currentNumRecords);
RecordHeader deleted = (RecordHeader)memIndex.remove(key);
}
}