/**
* CopyRight by Chinamobile
*
* KeyComparator.java
*/
package com.chinamobile.bcbsp.graph;
import com.sleepycat.je.*;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.Comparator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Key comparator for DB keys
*/
@SuppressWarnings("unchecked")
class KeyComparator implements Comparator,Serializable {
private static final long serialVersionUID = 1L;
/**
* Compares two DB keys.
*
* @param key1 first key
* @param key2 second key
*
* @return comparison result
*/
public int compare(Object key1, Object key2) {
byte[] k1 = (byte[]) key1;
byte[] k2 = (byte[]) key2;
return new BigInteger(k1).compareTo(new BigInteger(k2));
}
}
/**
* Fast queue implementation on top of Berkley DB Java Edition.
*
* This class is thread-safe.
*/
public final class BDBList {
public static final Log LOG = LogFactory.getLog(BDBList.class);
@SuppressWarnings("unused")
private final String dbEnvPath;
/**
* Berkley DB environment
*/
private final Environment dbEnv;
/**
* Berkley DB instance for the queue
*/
private Database queueDatabase;
/**
* Queue cache size - number of element operations it is allowed to loose in case of system crash.
*/
/**
* This queue name.
*/
private final String queueName;
/**
* Queue operation counter, which is used to sync the queue database to disk periodically.
*/
@SuppressWarnings("unused")
private int opsCounter;
/**
* Creates instance of persistent queue.
*
* @param dbEnvPath queue database environment directory path
* @param dbName descriptive queue name
* @param cacheSize how often to sync the queue to disk
*/
@SuppressWarnings("unchecked")
public BDBList(final String dbEnvPath,
final String dbName) {
this.dbEnvPath = dbEnvPath;
// Setup database environment
final EnvironmentConfig dbEnvConfig = new EnvironmentConfig();
dbEnvConfig.setTransactional(false);
dbEnvConfig.setAllowCreate(true);
dbEnvConfig.setCachePercent(30);
this.dbEnv = new Environment(new File(dbEnvPath),
dbEnvConfig);
// Setup non-transactional deferred-write queue database
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setTransactional(false);
dbConfig.setAllowCreate(true);
//dbConfig.setDeferredWrite(true);
dbConfig.setBtreeComparator(new KeyComparator());
dbConfig.setTemporary(true);
this.queueDatabase = dbEnv.openDatabase(null,
dbName,
dbConfig);
this.queueName = dbName;
}
/**
* Retrieves and returns element from the head of this queue.
*
* @return element from the head of the queue or null if queue is empty
*
* @throws IOException in case of disk IO failure
*/
public String poll() throws IOException {
final DatabaseEntry key = new DatabaseEntry();
final DatabaseEntry data = new DatabaseEntry();
final Cursor cursor = queueDatabase.openCursor(null, null);
try {
cursor.getFirst(key, data, LockMode.RMW);
if (data.getData() == null)
return null;
final String res = new String(data.getData(), "UTF-8");
cursor.delete();
return res;
} finally {
cursor.close();
}
}
/**
* Pushes element to the tail of this queue.
*
* @param element element
*
* @throws IOException in case of disk IO failure
*/
public synchronized void push(final String element) throws IOException {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry data = new DatabaseEntry();
Cursor cursor = queueDatabase.openCursor(null, null);
try {
cursor.getLast(key, data, LockMode.RMW);
BigInteger prevKeyValue;
if (key.getData() == null) {
prevKeyValue = BigInteger.valueOf(-1);
} else {
prevKeyValue = new BigInteger(key.getData());
}
BigInteger newKeyValue = prevKeyValue.add(BigInteger.ONE);
try {
final DatabaseEntry newKey = new DatabaseEntry(
newKeyValue.toByteArray());
final DatabaseEntry newData = new DatabaseEntry(
element.getBytes("UTF-8"));
queueDatabase.put(null, newKey, newData);
} catch (IOException e) {
LOG.error("[push]", e);
}
} finally {
cursor.close();
}
}
/**
* Returns the size of this queue.
*
* @return the size of the queue
*/
public long size() {
return queueDatabase.count();
}
public String getElement(int index){
DatabaseEntry data = new DatabaseEntry();
Cursor cursor = queueDatabase.openCursor(null, null);
BigInteger indexKey = new BigInteger(String.valueOf(index));
final DatabaseEntry findKey = new DatabaseEntry(
indexKey.toByteArray());
cursor.getSearchKey(findKey, data, LockMode.RMW);
String res = null;
try {
res = new String(data.getData(), "UTF-8");
} catch (UnsupportedEncodingException e) {
LOG.error("[getElement]", e);
}finally{
cursor.close();
}
return res;
}
public void setEelment(int index, String Element){
DatabaseEntry data = new DatabaseEntry();
Cursor cursor = queueDatabase.openCursor(null, null);
BigInteger indexKey = new BigInteger(String.valueOf(index));
final DatabaseEntry findKey = new DatabaseEntry(
indexKey.toByteArray());
cursor.getSearchKey(findKey, data, LockMode.DEFAULT);
DatabaseEntry replacementData;
try {
replacementData = new DatabaseEntry(Element.getBytes("UTF-8"));
cursor.putCurrent(replacementData);
} catch (UnsupportedEncodingException e) {
LOG.error("[setElement]", e);
} finally{
cursor.close();
}
}
public void deleteEelment(int index){
DatabaseEntry data = new DatabaseEntry();
Cursor cursor = queueDatabase.openCursor(null, null);
BigInteger indexKey = new BigInteger(String.valueOf(index));
final DatabaseEntry findKey = new DatabaseEntry(
indexKey.toByteArray());
cursor.getSearchKey(findKey, data, LockMode.RMW);
cursor.delete();
}
public void clear()
throws DatabaseException {
DatabaseEntry key = new DatabaseEntry();
DatabaseEntry data = new DatabaseEntry();
Cursor cursor = queueDatabase.openCursor(null, null);
try {
Boolean keysRenumbered = true;
OperationStatus status = OperationStatus.SUCCESS;
while (status == OperationStatus.SUCCESS) {
if (keysRenumbered) {
status = cursor.getFirst(key, data, LockMode.RMW);
keysRenumbered = false;
} else {
status = cursor.getNext(key, data, LockMode.RMW);
if (status == OperationStatus.SUCCESS) {
cursor.delete();
}
}
}
} finally {
cursor.close();
}
}
@SuppressWarnings("unchecked")
public void clean(){
try {
dbEnv.removeDatabase(null, queueName);
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setTransactional(false);
dbConfig.setAllowCreate(true);
dbConfig.setBtreeComparator(new KeyComparator());
dbConfig.setTemporary(true);
this.queueDatabase = dbEnv.openDatabase(null,
queueName,
dbConfig);
} catch (DatabaseNotFoundException e) {
LOG.error("[clean]", e);
} catch (DatabaseException e) {
LOG.error("[clean]", e);
}
}
public void close() {
queueDatabase.close();
dbEnv.close();
}
@SuppressWarnings("unused")
private static void deleteFile(File file){
if(file.exists()){
if(file.isFile()){
file.delete();
}else if(file.isDirectory()){
File files[] = file.listFiles();
for(int i=0;i<files.length;i++){
deleteFile(files[i]);
}
}
file.delete();
}
else{
//
}
}
}