package de.hub.emffrag.datastore;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class InMemoryDataStore implements IBaseDataStore, IBulkInsertExtension {
public static final Comparator<byte[]> byteComparator = new Comparator<byte[]>() {
@Override
public int compare(byte[] o1, byte[] o2) {
return compareBytes(o1, o2);
}
};
/**
* Comparator for byte arrays as used in HBase, supposed to be
* lexicographically.
*/
public static int compareBytes(byte[] left, byte[] right) {
for (int i = 0, j = 0; i < left.length && j < right.length; i++, j++) {
int a = (left[i] & 0xff);
int b = (right[j] & 0xff);
if (a != b) {
return Integer.valueOf(a).compareTo(Integer.valueOf(b)); // Integer.compare is not present in java 1.6
}
}
return Integer.valueOf(left.length).compareTo(Integer.valueOf(right.length)); // Integer.compare is not present in java 1.6
}
private static final byte[] EMTPY = new byte[] { 0 };
private TreeMap<byte[], byte[]> store = new TreeMap<byte[], byte[]>(byteComparator);
private final boolean fleeting;
public InMemoryDataStore(boolean fleeting) {
this.fleeting = fleeting;
}
@Override
public boolean bulkInsert(Map<byte[], byte[]> map) {
store.putAll(map);
return true;
}
public IScanExtension createScanningScanExtension() {
return new IScanExtension() {
@Override
public ICursor cursor(final byte[] key) {
return new ICursor() {
byte[] currentKey = null;
@Override
public InputStream openNextInputStream() {
byte[] value = store.get(currentKey);
if (value != null) {
return new ByteArrayInputStream(value);
} else {
return null;
}
}
@Override
public byte[] next() {
currentKey = store.tailMap(currentKey).entrySet().iterator().next().getKey();
return currentKey;
}
@Override
public boolean hasNext() {
if (currentKey == null) {
currentKey = key;
}
return store.tailMap(currentKey).entrySet().iterator().hasNext();
}
@Override
public void close() {
currentKey = null;
}
};
}
};
}
public IScanExtension createFirstOnlyScanExtension() {
return new IScanExtension() {
@Override
public ICursor cursor(byte[] key) {
final byte[] value = store.get(key);
if (value == null) {
return null;
}
return new ICursor() {
boolean first = true;
@Override
public InputStream openNextInputStream() {
return new ByteArrayInputStream(value);
}
@Override
public byte[] next() {
if (first) {
first = false;
return value;
} else {
throw new IndexOutOfBoundsException();
}
}
@Override
public boolean hasNext() {
return first;
}
@Override
public void close() {
}
};
}
};
}
@Override
public byte[] ceiling(byte[] key) {
return store.ceilingKey(key);
}
@Override
public byte[] floor(byte[] key) {
return store.floorKey(key);
}
@Override
public InputStream openInputStream(byte[] key) {
byte[] value = store.get(key);
if (value != null) {
return new ByteArrayInputStream(value);
} else {
return null;
}
}
@Override
public void close() {
}
@Override
public void flush() {
}
@Override
public OutputStream openOutputStream(final byte[] key) {
return new ByteArrayOutputStream() {
@Override
public void close() throws IOException {
super.close();
byte[] value = toByteArray();
store.put(key, fleeting ? EMTPY : value);
}
};
}
@Override
public boolean check(byte[] key) {
return store.get(key) == null;
}
@Override
public boolean checkAndCreate(byte[] key) {
boolean result = check(key);
if (result) {
store.put(key, EMTPY);
}
return result;
}
@Override
public void delete(byte[] key) {
store.remove(key);
}
// @Override
// public String toString() {
// StringBuffer buffer = new StringBuffer();
// buffer.append(uri + "\n");
// for (byte[] key: store.keySet()) {
// buffer.append("key: ");
// for (byte b: key) {
// buffer.append(b + " ");
// }
// buffer.append(", URI: " + uri + "/" + URIUtils.encode(key) + "\n");
// buffer.append("value: ");
// buffer.append(new String(store.get(key)) + "\n");
// }
// return buffer.toString();
// }
@Override
public void drop() {
store.clear();
}
}