/**
* GeDBIT.index.AbstractIndex 2006.05.09
*
* Copyright Information:
*
* Change Log:
* 2006.05.09: Created, by Rui Mao, Willard
*/
package GeDBIT.index;
import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import GeDBIT.dist.Metric;
import GeDBIT.type.IndexObject;
import GeDBIT.util.MckoiObjectIOManager;
import GeDBIT.util.ObjectIOManager;
/**
* The primary interface for distance-based index. Through AbstractIndex, the
* user can build a database index, or read a pre-built index from a file, and
* then do the search.
*
* @author Rui Mao, Willard
* @version 2006.07.24
*/
public abstract class AbstractIndex implements Index {
static final long serialVersionUID = 2659219513493819541L;
// name of the index node file
protected String fileName;
transient protected static String indexFileNameExtension = "index";
transient protected static String nodeFileNameExtension = "000";
transient protected ObjectIOManager oiom;
transient protected Logger logger;
// metric that this index is built over.
protected Metric metric;
// total number of data objects
protected int total_size;
// address of the index root node in the index node file
protected long root;
// parallel computing support
private int subtree = 0;
transient protected ObjectIOManager[] oioms = null;
private boolean flag = false;
public AbstractIndex(String fileName, List<? extends IndexObject> data,
Metric metric, Level debugLevel) {
if (fileName == null)
throw new IllegalArgumentException("fileName cannot be null!");
if (metric == null)
throw new IllegalArgumentException("metric cannot be null!");
if (data == null)
throw new IllegalArgumentException("data list cannot be null!");
if (debugLevel == null) {
System.err
.println("using default Debug Level: java.util.logging.Level.INFO");
debugLevel = Level.INFO;
}
this.flag = false;
this.fileName = fileName;
this.metric = metric;
total_size = data.size();
// 1. create the io manager, writeable
initOIOM(false);
openOIOM();
// 2. create the logger
logger = Logger.getLogger("GeDBIT.index");
// set the logger level;
logger.setLevel(debugLevel);
// init the Handler: currently use a console handler, in the future will
// probably use the
// FileHandler, or both
logger.addHandler(new ConsoleHandler());
/*
* try { logger.addHandler(new FileHandler(fileName+".log")); } catch
* (SecurityException e) { e.printStackTrace(); } catch (IOException e)
* { e.printStackTrace(); }
*/
}
// parallel computing support
public AbstractIndex(String fileName, List<? extends IndexObject> data,
Metric metric, Level debugLevel, int subtree) {
if (fileName == null)
throw new IllegalArgumentException("fileName cannot be null!");
if (metric == null)
throw new IllegalArgumentException("metric cannot be null!");
if (data == null)
throw new IllegalArgumentException("data list cannot be null!");
if (debugLevel == null) {
System.err
.println("using default Debug Level: java.util.logging.Level.INFO");
debugLevel = Level.INFO;
}
this.flag = true;
this.fileName = fileName;
this.metric = metric;
this.subtree = subtree;
total_size = data.size();
// 1. create the io manager, writeable
if (oioms == null) {
oioms = new MckoiObjectIOManager[subtree + 1];
}
for (int i = 0; i < subtree + 1; i++) {
initOIOM(false, i);
openOIOM(i);
}
// 2. create the logger
logger = Logger.getLogger("GeDBIT.index");
// set the logger level;
logger.setLevel(debugLevel);
// init the Handler: currently use a console handler, in the future will
// probably use the
// FileHandler, or both
logger.addHandler(new ConsoleHandler());
/*
* try { logger.addHandler(new FileHandler(fileName+".log")); } catch
* (SecurityException e) { e.printStackTrace(); } catch (IOException e)
* { e.printStackTrace(); }
*/
}
protected void initOIOM(boolean readOnly) {
oiom = new MckoiObjectIOManager(fileName, nodeFileNameExtension,
1024 * 1024 * 1024, "Java IO", 4, 128 * 1024, readOnly);
}
protected void initOIOM(boolean readOnly, int i) {
oioms[i] = new MckoiObjectIOManager(fileName + "-" + i,
nodeFileNameExtension, 1024 * 1024 * 1024, "Java IO", 4,
128 * 1024, readOnly);
}
protected void openOIOM() {
String indexFileName = fileName + "." + indexFileNameExtension;
String nodeFileName = fileName + "." + nodeFileNameExtension;
try {
if (!oiom.open()) {
throw new Error("Cannot open store for " + indexFileName + ":"
+ nodeFileName);
}
// System.out.println("OIOM.size = " + oiom.size() + "\n");
} catch (Exception e) {
e.printStackTrace();
}
}
protected void openOIOM(int i) {
String indexFileName = fileName + "-" + i + "."
+ indexFileNameExtension;
String nodeFileName = fileName + "-" + i + "." + nodeFileNameExtension;
try {
if (!oioms[i].open()) {
throw new Error("Cannot open store for " + indexFileName + ":"
+ nodeFileName);
}
// System.out.println("OIOM.size = " + oiom.size() + "\n");
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* (non-Javadoc)
*
* @see GeDBIT.index.Index#getMetric()
*/
public Metric getMetric() {
return this.metric;
}
public int getSubtree() {
return this.subtree;
}
public boolean getFlag() {
return flag;
}
/*
* (non-Javadoc)
*
* @see GeDBIT.index.Index#size()
*/
public int size() {
return total_size;
}
/*
* (non-Javadoc)
*
* @see GeDBIT.index.Index#preLoad(int)
*/
public void preLoad(int level) {
double startTime = 0;
double endTime = 0;
long memoryUsed = 0;
System.out.println("Start the preloading database into memory");
Runtime rt = Runtime.getRuntime();
memoryUsed = rt.totalMemory() - rt.freeMemory();
startTime = System.currentTimeMillis();
// hashing internal nodes first
LinkedList<PreLoadTask> nodeList = new LinkedList<PreLoadTask>();
PreLoadTask task = new PreLoadTask(root, 0);
nodeList.add(task);
int numPreLoadedNodes = 0;
while (!nodeList.isEmpty()) {
task = nodeList.removeFirst();
Object node = null;
try {
node = oiom.readPersistObject(task.nodeAddress);
numPreLoadedNodes++;
if (task.currentLevel < level) {
if (node instanceof InternalNode) {
for (int i = 0; i < ((InternalNode) node).childAddresses.length; i++)
nodeList.add(new PreLoadTask(
((InternalNode) node).childAddresses[i],
task.currentLevel + 1));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
endTime = (System.currentTimeMillis() - startTime) / 1000;
rt = Runtime.getRuntime();
memoryUsed = rt.totalMemory() - rt.freeMemory() - memoryUsed;
System.out.println("finish the preloading database into memory "
+ numPreLoadedNodes + " nodes loaded using " + endTime
+ " seconds " + memoryUsed + " byte memory");
}
private class PreLoadTask {
private long nodeAddress;
private int currentLevel;
private PreLoadTask(long nodeAddress, int currentLevel) {
this.nodeAddress = nodeAddress;
this.currentLevel = currentLevel;
}
}
/*
* (non-Javadoc)
*
* @see GeDBIT.index.Index#getAllPoints()
*/
public List<IndexObject> getAllPoints() {
return Cursor.getAllPoints(oiom, root);
}
public int getStoredDistanceNumber() {
return Cursor.getStoredDistanceNumber(oiom, root);
}
public int getStoredDistanceNumbers() {
return Cursor.getStoredDistanceNumbers(oioms, root, subtree);
}
/*
* (non-Javadoc)
*
* @see GeDBIT.index.Index#close()
*/
public void close() throws IOException {
oiom.close();
}
public void close(int i) throws IOException {
oioms[i].close();
}
/*
* (non-Javadoc)
*
* @see GeDBIT.index.Index#destroy()
*/
public void destroy() throws IOException {
if (flag) {
for (int i = 0; i < subtree + 1; i++) {
oioms[i].close();
// delete the oiom
boolean success = (new File(fileName + "-" + i + "."
+ nodeFileNameExtension)).delete();
if (!success) {
throw new IOException("Deletion failed.");
}
}
} else {
oiom.close();
// delete the oiom
boolean success = (new File(fileName + nodeFileNameExtension))
.delete();
if (!success) {
throw new IOException("Deletion failed.");
}
// delete the index file
success = (new File(fileName + indexFileNameExtension)).delete();
if (!success) {
throw new IOException("Deletion failed.");
}
}
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream in) throws IOException,
ClassNotFoundException {
in.defaultReadObject();
if (flag) {
if (oioms == null) {
oioms = new MckoiObjectIOManager[subtree + 1];
}
for (int i = 0; i < subtree; i++) {
File file = new File(fileName + "-" + i + "."
+ nodeFileNameExtension);
if (file.exists()) {
initOIOM(true, i);
openOIOM(i);
}
}
} else {
initOIOM(true);
openOIOM();
}
}
}