Phone app (based on Ali's Control for iotcloud benchmark) to control alarm in the...
[iot2.git] / benchmarks / other / PhoneInterface / Control / app / src / main / java / iotcloud / PendingTransaction.java
1 package iotcloud;
2
3 import java.util.Set;
4 import java.util.Map;
5 import java.util.HashSet;
6
7 import java.nio.ByteBuffer;
8
9
10 class PendingTransaction {
11
12     private Set<KeyValue> keyValueUpdateSet = null;
13     private Set<KeyValue> keyValueGuardSet = null;
14     private long arbitrator = -1;
15     private long clientLocalSequenceNumber = -1;
16     private long machineId = -1;
17
18     private int currentDataSize = 0;
19
20     public PendingTransaction(long _machineId) {
21         machineId = _machineId;
22         keyValueUpdateSet = new HashSet<KeyValue>();
23         keyValueGuardSet = new HashSet<KeyValue>();
24     }
25
26     /**
27      * Add a new key value to the updates
28      *
29      */
30     public void addKV(KeyValue newKV) {
31
32         KeyValue rmKV = null;
33
34         // Make sure there are no duplicates
35         for (KeyValue kv : keyValueUpdateSet) {
36             if (kv.getKey().equals(newKV.getKey())) {
37
38                 // Remove key if we are adding a newer version of the same key
39                 rmKV = kv;
40                 break;
41             }
42         }
43
44         // Remove key if we are adding a newer version of the same key
45         if (rmKV != null) {
46             keyValueUpdateSet.remove(rmKV);
47             currentDataSize -= rmKV.getSize();
48         }
49
50         // Add the key to the hash set
51         keyValueUpdateSet.add(newKV);
52         currentDataSize += newKV.getSize();
53     }
54
55     /**
56      * Add a new key value to the guard set
57      *
58      */
59     public void addKVGuard(KeyValue newKV) {
60         // Add the key to the hash set
61         keyValueGuardSet.add(newKV);
62         currentDataSize += newKV.getSize();
63     }
64
65     /**
66      * Checks if the arbitrator is the same
67      */
68     public boolean checkArbitrator(long arb) {
69         if (arbitrator == -1) {
70             arbitrator = arb;
71             return true;
72         }
73
74         return arb == arbitrator;
75     }
76
77     /**
78      * Get the transaction arbitrator
79      */
80     public long getArbitrator() {
81         return arbitrator;
82     }
83
84     /**
85      * Get the key value update set
86      */
87     public Set<KeyValue> getKVUpdates() {
88         return keyValueUpdateSet;
89     }
90
91     /**
92      * Get the key value update set
93      */
94     public Set<KeyValue> getKVGuard() {
95         return keyValueGuardSet;
96     }
97
98     public void setClientLocalSequenceNumber(long _clientLocalSequenceNumber) {
99         clientLocalSequenceNumber = _clientLocalSequenceNumber;
100     }
101
102     public long getClientLocalSequenceNumber() {
103         return clientLocalSequenceNumber;
104     }
105
106     public long getMachineId() {
107         return machineId;
108     }
109
110     public boolean evaluateGuard(Map<IoTString, KeyValue> keyValTableCommitted, Map<IoTString, KeyValue> keyValTableSpeculative, Map<IoTString, KeyValue> keyValTablePendingTransSpeculative) {
111         for (KeyValue kvGuard : keyValueGuardSet) {
112
113             // First check if the key is in the speculative table, this is the value of the latest assumption
114             KeyValue kv = keyValTablePendingTransSpeculative.get(kvGuard.getKey());
115
116
117             if (kv == null) {
118                 // if it is not in the pending trans table then check the speculative table and use that
119                 // value as our latest assumption
120                 kv = keyValTableSpeculative.get(kvGuard.getKey());
121             }
122
123
124             if (kv == null) {
125                 // if it is not in the speculative table then check the committed table and use that
126                 // value as our latest assumption
127                 kv = keyValTableCommitted.get(kvGuard.getKey());
128             }
129
130             if (kvGuard.getValue() != null) {
131                 if ((kv == null) || (!kvGuard.getValue().equals(kv.getValue()))) {
132                     return false;
133                 }
134             } else {
135                 if (kv != null) {
136                     return false;
137                 }
138             }
139         }
140         return true;
141     }
142
143     public Transaction createTransaction() {
144
145         Transaction newTransaction = new Transaction();
146         int transactionPartCount = 0;
147
148         // Convert all the data into a byte array so we can start partitioning
149         byte[] byteData = convertDataToBytes();
150
151         int currentPosition = 0;
152         int remaining = byteData.length;
153
154         while (remaining > 0) {
155
156             Boolean isLastPart = false;
157             // determine how much to copy
158             int copySize = TransactionPart.MAX_NON_HEADER_SIZE;
159             if (remaining <= TransactionPart.MAX_NON_HEADER_SIZE) {
160                 copySize = remaining;
161                 isLastPart = true; // last bit of data so last part
162             }
163
164             // Copy to a smaller version
165             byte[] partData = new byte[copySize];
166             System.arraycopy(byteData, currentPosition, partData, 0, copySize);
167
168             TransactionPart part = new TransactionPart(null, machineId, arbitrator, clientLocalSequenceNumber, transactionPartCount, partData, isLastPart);
169             newTransaction.addPartEncode(part);
170
171             // Update position, count and remaining
172             currentPosition += copySize;
173             transactionPartCount++;
174             remaining -= copySize;
175         }
176
177         // Add the Guard Conditions
178         for (KeyValue kv : keyValueGuardSet) {
179             newTransaction.addGuardKV(kv);
180         }
181
182         //  Add the updates
183         for (KeyValue kv : keyValueUpdateSet) {
184             newTransaction.addUpdateKV(kv);
185         }
186
187         return newTransaction;
188     }
189
190     private byte[] convertDataToBytes() {
191
192         // Calculate the size of the data
193         //int sizeOfData = 2 * Integer.BYTES; // Number of Update KV's and Guard KV's
194         int sizeOfData = 2 * Integer.SIZE/8; // Number of Update KV's and Guard KV's
195         sizeOfData += currentDataSize;
196
197         // Data handlers and storage
198         byte[] dataArray = new byte[sizeOfData];
199         ByteBuffer bbEncode = ByteBuffer.wrap(dataArray);
200
201         // Encode the size of the updates and guard sets
202         bbEncode.putInt(keyValueGuardSet.size());
203         bbEncode.putInt(keyValueUpdateSet.size());
204
205         // Encode all the guard conditions
206         for (KeyValue kv : keyValueGuardSet) {
207             kv.encode(bbEncode);
208         }
209
210         // Encode all the updates
211         for (KeyValue kv : keyValueUpdateSet) {
212             kv.encode(bbEncode);
213         }
214
215         return bbEncode.array();
216     }
217 }