5 import java.util.HashSet;
7 import javax.script.ScriptException;
8 import java.lang.NullPointerException;
9 import java.nio.ByteBuffer;
12 class PendingTransaction {
14 private Set<KeyValue> keyValueUpdateSet = null;
15 private Set<KeyValue> keyValueGuardSet = null;
16 private long arbitrator = -1;
17 private long clientLocalSequenceNumber = -1;
18 private long machineId = -1;
20 private int currentDataSize = 0;
22 public PendingTransaction(long _machineId) {
23 machineId = _machineId;
24 keyValueUpdateSet = new HashSet<KeyValue>();
25 keyValueGuardSet = new HashSet<KeyValue>();
29 * Add a new key value to the updates
32 public void addKV(KeyValue newKV) {
36 // Make sure there are no duplicates
37 for (KeyValue kv : keyValueUpdateSet) {
38 if (kv.getKey().equals(newKV.getKey())) {
40 // Remove key if we are adding a newer version of the same key
46 // Remove key if we are adding a newer version of the same key
48 keyValueUpdateSet.remove(rmKV);
49 currentDataSize -= rmKV.getSize();
52 // Add the key to the hash set
53 keyValueUpdateSet.add(newKV);
54 currentDataSize += newKV.getSize();
58 * Add a new key value to the guard set
61 public void addKVGuard(KeyValue newKV) {
62 // Add the key to the hash set
63 keyValueGuardSet.add(newKV);
64 currentDataSize += newKV.getSize();
68 * Checks if the arbitrator is the same
70 public boolean checkArbitrator(long arb) {
71 if (arbitrator == -1) {
76 return arb == arbitrator;
80 * Get the transaction arbitrator
82 public long getArbitrator() {
87 * Get the key value update set
89 public Set<KeyValue> getKVUpdates() {
90 return keyValueUpdateSet;
94 * Get the key value update set
96 public Set<KeyValue> getKVGuard() {
97 return keyValueGuardSet;
100 public void setClientLocalSequenceNumber(long _clientLocalSequenceNumber) {
101 clientLocalSequenceNumber = _clientLocalSequenceNumber;
104 public long getClientLocalSequenceNumber() {
105 return clientLocalSequenceNumber;
108 public long getMachineId() {
112 public boolean evaluateGuard(Map<IoTString, KeyValue> keyValTableCommitted, Map<IoTString, KeyValue> keyValTableSpeculative, Map<IoTString, KeyValue> keyValTablePendingTransSpeculative) {
113 for (KeyValue kvGuard : keyValueGuardSet) {
115 // First check if the key is in the speculative table, this is the value of the latest assumption
116 KeyValue kv = keyValTablePendingTransSpeculative.get(kvGuard.getKey());
120 // if it is not in the pending trans table then check the speculative table and use that
121 // value as our latest assumption
122 kv = keyValTableSpeculative.get(kvGuard.getKey());
127 // if it is not in the speculative table then check the committed table and use that
128 // value as our latest assumption
129 kv = keyValTableCommitted.get(kvGuard.getKey());
132 if (kvGuard.getValue() != null) {
133 if ((kv == null) || (!kvGuard.getValue().equals(kv.getValue()))) {
145 public Transaction createTransaction() {
147 Transaction newTransaction = new Transaction();
148 int transactionPartCount = 0;
150 // Convert all the data into a byte array so we can start partitioning
151 byte[] byteData = convertDataToBytes();
153 int currentPosition = 0;
154 int remaining = byteData.length;
156 while (remaining > 0) {
158 Boolean isLastPart = false;
159 // determine how much to copy
160 int copySize = TransactionPart.MAX_NON_HEADER_SIZE;
161 if (remaining <= TransactionPart.MAX_NON_HEADER_SIZE) {
162 copySize = remaining;
163 isLastPart = true; // last bit of data so last part
166 // Copy to a smaller version
167 byte[] partData = new byte[copySize];
168 System.arraycopy(byteData, currentPosition, partData, 0, copySize);
170 TransactionPart part = new TransactionPart(null, machineId, arbitrator, clientLocalSequenceNumber, transactionPartCount, partData, isLastPart);
171 newTransaction.addPartEncode(part);
173 // Update position, count and remaining
174 currentPosition += copySize;
175 transactionPartCount++;
176 remaining -= copySize;
179 // Add the Guard Conditions
180 for (KeyValue kv : keyValueGuardSet) {
181 newTransaction.addGuardKV(kv);
185 for (KeyValue kv : keyValueUpdateSet) {
186 newTransaction.addUpdateKV(kv);
189 return newTransaction;
192 private byte[] convertDataToBytes() {
194 // Calculate the size of the data
195 int sizeOfData = 2 * Integer.BYTES; // Number of Update KV's and Guard KV's
196 sizeOfData += currentDataSize;
198 // Data handlers and storage
199 byte[] dataArray = new byte[sizeOfData];
200 ByteBuffer bbEncode = ByteBuffer.wrap(dataArray);
202 // Encode the size of the updates and guard sets
203 bbEncode.putInt(keyValueGuardSet.size());
204 bbEncode.putInt(keyValueUpdateSet.size());
206 // Encode all the guard conditions
207 for (KeyValue kv : keyValueGuardSet) {
211 // Encode all the updates
212 for (KeyValue kv : keyValueUpdateSet) {
216 return bbEncode.array();