5 import java.util.HashSet;
7 import java.nio.ByteBuffer;
10 class PendingTransaction {
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;
18 private int currentDataSize = 0;
20 public PendingTransaction(long _machineId) {
21 machineId = _machineId;
22 keyValueUpdateSet = new HashSet<KeyValue>();
23 keyValueGuardSet = new HashSet<KeyValue>();
27 * Add a new key value to the updates
30 public void addKV(KeyValue newKV) {
34 // Make sure there are no duplicates
35 for (KeyValue kv : keyValueUpdateSet) {
36 if (kv.getKey().equals(newKV.getKey())) {
38 // Remove key if we are adding a newer version of the same key
44 // Remove key if we are adding a newer version of the same key
46 keyValueUpdateSet.remove(rmKV);
47 currentDataSize -= rmKV.getSize();
50 // Add the key to the hash set
51 keyValueUpdateSet.add(newKV);
52 currentDataSize += newKV.getSize();
56 * Add a new key value to the guard set
59 public void addKVGuard(KeyValue newKV) {
60 // Add the key to the hash set
61 keyValueGuardSet.add(newKV);
62 currentDataSize += newKV.getSize();
66 * Checks if the arbitrator is the same
68 public boolean checkArbitrator(long arb) {
69 if (arbitrator == -1) {
74 return arb == arbitrator;
78 * Get the transaction arbitrator
80 public long getArbitrator() {
85 * Get the key value update set
87 public Set<KeyValue> getKVUpdates() {
88 return keyValueUpdateSet;
92 * Get the key value update set
94 public Set<KeyValue> getKVGuard() {
95 return keyValueGuardSet;
98 public void setClientLocalSequenceNumber(long _clientLocalSequenceNumber) {
99 clientLocalSequenceNumber = _clientLocalSequenceNumber;
102 public long getClientLocalSequenceNumber() {
103 return clientLocalSequenceNumber;
106 public long getMachineId() {
110 public boolean evaluateGuard(Map<IoTString, KeyValue> keyValTableCommitted, Map<IoTString, KeyValue> keyValTableSpeculative, Map<IoTString, KeyValue> keyValTablePendingTransSpeculative) {
111 for (KeyValue kvGuard : keyValueGuardSet) {
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());
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());
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());
130 if (kvGuard.getValue() != null) {
131 if ((kv == null) || (!kvGuard.getValue().equals(kv.getValue()))) {
143 public Transaction createTransaction() {
145 Transaction newTransaction = new Transaction();
146 int transactionPartCount = 0;
148 // Convert all the data into a byte array so we can start partitioning
149 byte[] byteData = convertDataToBytes();
151 int currentPosition = 0;
152 int remaining = byteData.length;
154 while (remaining > 0) {
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
164 // Copy to a smaller version
165 byte[] partData = new byte[copySize];
166 System.arraycopy(byteData, currentPosition, partData, 0, copySize);
168 TransactionPart part = new TransactionPart(null, machineId, arbitrator, clientLocalSequenceNumber, transactionPartCount, partData, isLastPart);
169 newTransaction.addPartEncode(part);
171 // Update position, count and remaining
172 currentPosition += copySize;
173 transactionPartCount++;
174 remaining -= copySize;
177 // Add the Guard Conditions
178 for (KeyValue kv : keyValueGuardSet) {
179 newTransaction.addGuardKV(kv);
183 for (KeyValue kv : keyValueUpdateSet) {
184 newTransaction.addUpdateKV(kv);
187 return newTransaction;
190 private byte[] convertDataToBytes() {
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;
197 // Data handlers and storage
198 byte[] dataArray = new byte[sizeOfData];
199 ByteBuffer bbEncode = ByteBuffer.wrap(dataArray);
201 // Encode the size of the updates and guard sets
202 bbEncode.putInt(keyValueGuardSet.size());
203 bbEncode.putInt(keyValueUpdateSet.size());
205 // Encode all the guard conditions
206 for (KeyValue kv : keyValueGuardSet) {
210 // Encode all the updates
211 for (KeyValue kv : keyValueUpdateSet) {
215 return bbEncode.array();