class Slot implements Liveness {
static final int SLOT_SIZE=2048;
+ static final int RESERVED_SPACE=64;
static final int HMAC_SIZE=32;
private long seqnum;
private Vector<Entry> entries;
private int livecount;
private boolean seqnumlive;
+ private int freespace;
Slot(long _seqnum, long _machineid, byte[] _prevhmac, byte[] _hmac) {
seqnum=_seqnum;
entries=new Vector<Entry>();
livecount=1;
seqnumlive=true;
+ freespace = SLOT_SIZE - getBaseSize();
}
Slot(long _seqnum, long _machineid, byte[] _prevhmac) {
void addEntry(Entry e) {
entries.add(e);
livecount++;
+ freespace -= e.getSize();
}
+ boolean hasSpace(Entry e) {
+ int newfreespace = freespace - e.getSize();
+ return newfreespace > RESERVED_SPACE;
+ }
+
+ boolean canFit(Entry e) {
+ int newfreespace = freespace - e.getSize();
+ return newfreespace >= 0;
+ }
+
Vector<Entry> getEntries() {
return entries;
}
return array;
}
+ int getBaseSize() {
+ return 2*HMAC_SIZE+2*Long.BYTES+Integer.BYTES;
+ }
+
+ Vector<Entry> getLiveEntries() {
+ Vector<Entry> liveEntries=new Vector<Entry>();
+ for(Entry entry: entries)
+ if (entry.isLive())
+ liveEntries.add(entry);
+
+ if (seqnumlive)
+ liveEntries.add(new LastMessage(this, machineid, seqnum));
+
+ return liveEntries;
+ }
+
long getSequenceNumber() {
return seqnum;
}
package iotcloud;
import java.util.HashMap;
import java.util.Arrays;
+import java.util.Vector;
import javax.crypto.spec.*;
import javax.crypto.*;
private long localmachineid;
private TableStatus lastTableStatus;
static final int FREE_SLOTS = 10;
+ static final int FORCED_RESIZE_INCREMENT = 20;
public Table(String baseurl, String password, long _localmachineid) {
localmachineid=_localmachineid;
}
public IoTString put(IoTString key, IoTString value) {
+ while(true) {
+ KeyValue oldvalue=table.get(key);
+ if (tryput(key, value)) {
+ return oldvalue.getValue();
+ }
+ }
+ }
+
+ private boolean tryput(IoTString key, IoTString value) {
Slot s=new Slot(sequencenumber+1, localmachineid, buffer.getSlot(sequencenumber).getHMAC());
+ boolean forcedresize = false;
+ long seqn = buffer.getOldestSeqNum();
+
if ((numslots - buffer.size()) < FREE_SLOTS) {
//have to check whether we have enough free slots
- long seqn = buffer.getNewestSeqNum() + 1 - numslots;
- for(int i=0; i < FREE_SLOTS; i++, seqn--) {
+ seqn = buffer.getNewestSeqNum() + 1 - numslots;
+ for(int i=0; i < FREE_SLOTS; i++, seqn++) {
Slot prevslot=buffer.getSlot(seqn);
if (!prevslot.isLive())
continue;
-
+ Vector<Entry> liveentries = prevslot.getLiveEntries();
+ for(Entry liveentry:liveentries) {
+ if (s.hasSpace(liveentry))
+ s.addEntry(liveentry);
+ else if (i==0) {
+ if (s.canFit(liveentry))
+ s.addEntry(liveentry);
+ else
+ forcedresize = true;
+ }
+ }
}
}
+ KeyValue kv=new KeyValue(s, key, value);
+ boolean insertedkv=false;
+ if (s.hasSpace(kv)) {
+ s.addEntry(kv);
+ insertedkv=true;
+ }
-
- return null;
+ long newestseqnum=buffer.getNewestSeqNum();
+ search:
+ for(;seqn<=newestseqnum;seqn++) {
+ Slot prevslot=buffer.getSlot(seqn);
+ if (!prevslot.isLive())
+ continue;
+ Vector<Entry> liveentries = prevslot.getLiveEntries();
+ for(Entry liveentry:liveentries) {
+ if (s.hasSpace(liveentry))
+ s.addEntry(liveentry);
+ else
+ break search;
+ }
+ }
+
+ int max=0;
+ if (forcedresize)
+ max = numslots + FORCED_RESIZE_INCREMENT;
+ Slot[] array=cloud.putSlot(s, max);
+ if (array == null)
+ array = new Slot[] {s};
+ else
+ insertedkv=false;
+
+ validateandupdate(array); // update data structure
+
+ return insertedkv;
}
private void validateandupdate(Slot[] newslots) {