package org.deuce.transaction.estmstats;
import org.deuce.transaction.estmstats.Context.LockTable;
import org.deuce.transaction.estmstats.field.ReadFieldAccess;
import org.deuce.transform.Exclude;
/**
* @author Vincent Gramoli
*/
@Exclude
final public class ReadSet {
/** An array of read entries */
private ReadFieldAccess[] entries;
/** The number of read entries */
private int size;
/**
* Initialize the read set with a given number of elements
*
* @param initialCapacity the number of elements
*/
public ReadSet(int initialCapacity) {
entries = new ReadFieldAccess[initialCapacity];
size = 0;
initArray(0);
}
public int size() {
return size;
}
/**
* Clear the read set by resetting its size
*/
public void clear() {
size = 0;
}
/**
* Copy the last-read-entries field to the readset.
* Used to switched from lightweight validation to full validation
* in an elastic transaction
*
* @param lre last-read-entries field to be copied
*/
public void copy(LastReadEntries lre) {
int l = lre.getSize();
ReadFieldAccess[] e = new ReadFieldAccess[l];
System.arraycopy(lre.entries, 0, e, 0, l);
entries = e;
}
/**
* Add a read entry to the read set
* and allocates length^2 new entries if full
*
* @param reference the object of the field
* @param field the field
* @param hash its identifier
* @param lock its version / owner
*/
public void add(Object reference, long field, int hash, int lock) {
/* unable to catch this exception within a transaction
* even though it would be faster to try instead of guarding
try {
ReadFieldAccess r = entries[size++];
r.init(reference, field, hash, lock);
} catch (ArrayIndexOutOfBoundsException x) {
int l = entries.length;
ReadFieldAccess[] e = new ReadFieldAccess[l << 1];
System.arraycopy(entries, 0, e, 0, l);
entries = e;
initArray(l);
ReadFieldAccess r = entries[size++];
r.init(reference, field, hash, lock);
} */
if (size >= entries.length) {
int l = entries.length;
ReadFieldAccess[] e = new ReadFieldAccess[l << 1];
System.arraycopy(entries, 0, e, 0, l);
entries = e;
initArray(l);
}
assert size < entries.length;
ReadFieldAccess r = entries[size++];
r.init(reference, field, hash, lock);
}
/**
* Return the size of the read-set
*/
public int getSize() {
return size;
}
/**
* Validate the transaction
* Check that the version of read locations, which
* are maintained by the elastic tx, are consistent
*
* @param id the identifier
* @return true if the validation is successful
*/
public boolean validate(int id) {
int lock;
for (int i = 0; i < size; i++) {
// Throws an exception if validation fails
ReadFieldAccess r = entries[i];
lock = LockTable.checkLock(r.getHash(), id);
if (lock >= 0 && lock != r.getLock()) {
// Other version: cannot validate
return false;
}
}
return true;
}
/**
* Indicates whether the given field corresponds
* to an existing read entry of the read set
*
* @param obj the object of the field
* @param field the accessed field
* @return true is the read set contains the field
*/
public boolean contains(Object obj, long field) {
for (int i = 0; i < size; i++) {
ReadFieldAccess r = entries[i];
if (r.getField() == field && r.getReference() == obj)
return true;
}
return false;
}
/**
* Allocating more space for the array
*
* @param fromIndex index from where allocation is done
*/
private void initArray(int fromIndex) {
int l = entries.length;
for (int i = fromIndex; i < l; i++)
entries[i] = new ReadFieldAccess();
}
}