blob: 55de05a306c8dd1fcdb97dfbef7251ab290f2249 [file] [log] [blame]
package net.onrc.onos.datastore;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.stanford.ramcloud.JRamCloud;
import edu.stanford.ramcloud.JRamCloud.ObjectDoesntExistException;
import edu.stanford.ramcloud.JRamCloud.ObjectExistsException;
import edu.stanford.ramcloud.JRamCloud.RejectRules;
import edu.stanford.ramcloud.JRamCloud.WrongVersionException;
/**
* Class to represent a Table in RAMCloud
*
*/
public class RCTable {
private static final Logger log = LoggerFactory.getLogger(RCTable.class);
private static final ConcurrentHashMap<String, RCTable> table_map = new ConcurrentHashMap<>();
/**
*
* @param table
* Table to drop.
* @note Instance passed must not be use after successful call.
*
*/
public static void dropTable(RCTable table) {
JRamCloud rcClient = RCClient.getClient();
// TODO mark the table instance as dropped?
rcClient.dropTable(table.getTableName());
table_map.remove(table.getTableName());
}
public static RCTable getTable(String tableName) {
RCTable table = table_map.get(tableName);
if (table == null) {
RCTable new_table = new RCTable(tableName);
RCTable existing_table = table_map
.putIfAbsent(tableName, new_table);
if (existing_table != null) {
return existing_table;
} else {
return new_table;
}
}
return table;
}
public static class Entry {
public final byte[] key;
public byte[] value;
public long version;
public Entry(byte[] key, byte[] value, long version) {
this.key = key;
this.value = value;
this.version = version;
}
}
// finally the Table itself
private final long rcTableId;
private final String rcTableName;
// private boolean isDropped = false;
/**
*
* @note rcTableName must be unique cluster wide.
* @param rcTableName
*/
private RCTable(String rcTableName) {
JRamCloud rcClient = RCClient.getClient();
this.rcTableName = rcTableName;
// FIXME Is it better to create table here or at getTable
this.rcTableId = rcClient.createTable(rcTableName);
}
public long getTableId() {
return this.rcTableId;
}
public String getTableName() {
return this.rcTableName;
}
// TODO: Enumerate whole table?
/**
* Create a Key-Value entry on table.
*
* @param key
* @param value
* @return version of the created entry
* @throws ObjectExistsException
*/
public long create(final byte[] key, final byte[] value)
throws ObjectExistsException {
JRamCloud rcClient = RCClient.getClient();
RejectRules rules = rcClient.new RejectRules();
rules.setExists();
long updated_version = rcClient.writeRule(this.rcTableId, key, value,
rules);
return updated_version;
}
/**
* Create a Key-Value entry on table, without existance checking.
*
* @param key
* @param value
* @return version of the created entry
*/
public long forceCreate(final byte[] key, final byte[] value) {
JRamCloud rcClient = RCClient.getClient();
long updated_version = rcClient.write(this.rcTableId, key, value);
return updated_version;
}
/**
* Read a Key-Value entry from table.
*
* @param key
* @return Corresponding {@link Entry}
* @throws ObjectDoesntExistException
*/
public Entry read(final byte[] key) throws ObjectDoesntExistException {
JRamCloud rcClient = RCClient.getClient();
// FIXME underlying JRamCloud cannot detect "not exist"
// RejectRules rules = rcClient.new RejectRules();
// rules.setDoesntExists();
// JRamCloud.Object rcObj = rcClient.read(this.rcTableId, key, rules);
JRamCloud.Object rcObj = rcClient.read(this.rcTableId, key);
return new Entry(rcObj.key, rcObj.value, rcObj.version);
}
/**
* Update an existing Key-Value entry in table.
*
* @param key
* @param value
* @param version
* expected version in the data store
* @return version after update
* @throws ObjectDoesntExistException
* @throws WrongVersionException
*/
public long update(final byte[] key, final byte[] value, final long version)
throws ObjectDoesntExistException, WrongVersionException {
JRamCloud rcClient = RCClient.getClient();
RejectRules rules = rcClient.new RejectRules();
rules.setDoesntExists();
rules.setNeVersion(version);
long updated_version = rcClient.writeRule(this.rcTableId, key, value,
rules);
return updated_version;
}
/**
* Update an existing Key-Value entry in table, without checking version.
*
* @param key
* @param value
* @return version after update
* @throws ObjectDoesntExistException
*/
public long update(final byte[] key, final byte[] value)
throws ObjectDoesntExistException {
JRamCloud rcClient = RCClient.getClient();
RejectRules rules = rcClient.new RejectRules();
rules.setDoesntExists();
long updated_version = rcClient.writeRule(this.rcTableId, key, value,
rules);
return updated_version;
}
/**
* Remove an existing Key-Value entry in table
*
* @param key
* @param version
* expected version in the data store
* @return version of removed object
* @throws ObjectDoesntExistException
* @throws WrongVersionException
*/
public long delete(final byte[] key, final long version)
throws ObjectDoesntExistException, WrongVersionException {
JRamCloud rcClient = RCClient.getClient();
// FIXME underlying JRamCloud does not support cond. remove now
RejectRules rules = rcClient.new RejectRules();
rules.setDoesntExists();
rules.setNeVersion(version);
long removed_version = rcClient.remove(this.rcTableId, key, rules);
return removed_version;
}
/**
* Remove a Key-Value entry in table
*
* @param key
* @return version of removed object or -1, if it did not exist.
*/
public long forceDelete(final byte[] key) {
JRamCloud rcClient = RCClient.getClient();
long removed_version = rcClient.remove(this.rcTableId, key);
return removed_version;
}
}