1 24 25 package com.mckoi.database; 26 27 import com.mckoi.util.IntegerVector; 28 import java.io.*; 29 30 36 37 final class MasterTableJournal { 38 39 42 final static byte TABLE_ADD = 1; final static byte TABLE_REMOVE = 2; final static byte TABLE_UPDATE_ADD = 5; final static byte TABLE_UPDATE_REMOVE = 6; 49 53 private long commit_id; 54 55 56 59 private int table_id; 60 61 64 private int journal_entries; 65 66 70 private byte[] command_journal; 71 72 77 private IntegerVector command_parameters; 78 79 82 MasterTableJournal(int table_id) { 83 this.table_id = table_id; 84 command_journal = new byte[16]; 85 command_parameters = new IntegerVector(32); 86 } 87 88 MasterTableJournal() { 89 this(-1); 90 } 91 92 96 void setCommitID(long commit_id) { 97 this.commit_id = commit_id; 98 } 99 100 103 static boolean isAddCommand(byte command) { 104 return ((command & 0x03) == TABLE_ADD); 105 } 106 107 110 static boolean isRemoveCommand(byte command) { 111 return ((command & 0x03) == TABLE_REMOVE); 112 } 113 114 117 private void addCommand(byte command) { 118 if (journal_entries >= command_journal.length) { 119 int grow_size = Math.min(4000, journal_entries); 121 grow_size = Math.max(4, grow_size); 122 byte[] new_command_journal = new byte[journal_entries + grow_size]; 123 System.arraycopy(command_journal, 0, new_command_journal, 0, 124 journal_entries); 125 command_journal = new_command_journal; 126 } 127 128 command_journal[journal_entries] = command; 129 ++journal_entries; 130 } 131 132 135 private void addParameter(int param) { 136 command_parameters.addInt(param); 137 } 138 139 142 private void removeTopEntries(int n) { 143 journal_entries = journal_entries - n; 144 command_parameters.crop(0, command_parameters.size() - n); 145 } 146 147 150 void addEntry(byte command, int row_index) { 151 addCommand(command); 152 addParameter(row_index); 153 } 154 155 159 162 long getCommitID() { 163 return commit_id; 164 } 165 166 169 int getTableID() { 170 return table_id; 171 } 172 173 176 int entries() { 177 return journal_entries; 178 } 179 180 183 byte getCommand(int n) { 184 return command_journal[n]; 185 } 186 187 190 int getRowIndex(int n) { 191 return command_parameters.intAt(n); 192 } 193 194 200 int[] normalizedAddedRows() { 201 IntegerVector list = new IntegerVector(); 202 int size = entries(); 203 for (int i = 0; i < size; ++i) { 204 byte tc = getCommand(i); 205 if (tc == TABLE_ADD || tc == TABLE_UPDATE_ADD) { 206 int row_index = getRowIndex(i); 207 list.addInt(row_index); 209 } 210 else if (tc == TABLE_REMOVE || tc == TABLE_UPDATE_REMOVE) { 211 int row_index = getRowIndex(i); 214 int found_at = list.indexOf(row_index); 215 if (found_at != -1) { 216 list.removeIntAt(found_at); 217 } 218 } 219 else { 220 throw new Error ("Unknown command in journal."); 221 } 222 } 223 224 return list.toIntArray(); 225 } 226 227 231 int[] normalizedRemovedRows() { 232 IntegerVector list = new IntegerVector(); 233 int size = entries(); 234 for (int i = 0; i < size; ++i) { 235 byte tc = getCommand(i); 236 if (tc == TABLE_REMOVE || tc == TABLE_UPDATE_REMOVE) { 237 int row_index = getRowIndex(i); 239 list.addInt(row_index); 240 } 241 } 242 return list.toIntArray(); 243 } 244 245 255 IntegerVector[] allChangeInformation() { 256 IntegerVector[] lists = new IntegerVector[3]; 257 for (int i = 0; i < 3; ++i) { 258 lists[i] = new IntegerVector(); 259 } 260 int size = entries(); 261 for (int i = 0; i < size; ++i) { 262 byte tc = getCommand(i); 263 int row_index = getRowIndex(i); 264 if (tc == TABLE_ADD) { 265 lists[0].addInt(row_index); 266 } 267 else if (tc == TABLE_REMOVE) { 268 lists[1].addInt(row_index); 269 } 270 else if (tc == TABLE_UPDATE_ADD || tc == TABLE_UPDATE_REMOVE) { 271 lists[2].addInt(row_index); 272 } 273 else { 274 throw new RuntimeException ("Don't understand journal command."); 275 } 276 } 277 return lists; 278 } 279 280 287 void rollbackEntries(int n) { 288 if (n > journal_entries) { 289 throw new RuntimeException ( 290 "Trying to roll back more journal entries than are in the journal."); 291 } 292 293 IntegerVector to_add = new IntegerVector(); 294 295 int size = entries(); 297 for (int i = size - n; i < size; ++i) { 298 byte tc = getCommand(i); 299 if (tc == TABLE_ADD || tc == TABLE_UPDATE_ADD) { 300 to_add.addInt(getRowIndex(i)); 301 } 302 } 303 304 removeTopEntries(n); 306 for (int i = 0; i < to_add.size(); ++i) { 308 addEntry(TABLE_ADD, to_add.intAt(i)); 309 addEntry(TABLE_REMOVE, to_add.intAt(i)); 310 } 311 312 } 313 314 315 316 318 324 void testCommitClash(DataTableDef table_def, MasterTableJournal journal) 325 throws TransactionException { 326 330 for (int i = 0; i < entries(); ++i) { 331 byte tc = getCommand(i); 332 if (isRemoveCommand(tc)) { int row_index = getRowIndex(i); 334 for (int n = 0; n < journal.entries(); ++n) { 336 if (isRemoveCommand(journal.getCommand(n)) && 338 journal.getRowIndex(n) == row_index) { 339 throw new TransactionException( 340 TransactionException.ROW_REMOVE_CLASH, 341 "Concurrent Serializable Transaction Conflict(1): " + 342 "Current row remove clash ( row: " + row_index + ", table: " + 343 table_def.getTableName() + " )"); 344 } 345 } 346 } 348 } 349 } 350 351 352 354 360 void readFrom(DataInputStream din) throws IOException { 361 commit_id = din.readInt(); 362 table_id = din.readInt(); 363 364 journal_entries = din.readInt(); 365 command_journal = new byte[journal_entries]; 366 din.readFully(command_journal, 0, journal_entries); 367 int size = din.readInt(); 368 for (int i = 0; i < size; ++i) { 369 command_parameters.addInt(din.readInt()); 370 } 371 } 372 373 376 public String toString() { 377 StringBuffer buf = new StringBuffer (); 378 buf.append("[MasterTableJournal] ["); 379 buf.append(commit_id); 380 buf.append("] ("); 381 for (int i = 0; i < entries(); ++i) { 382 byte c = getCommand(i); 383 int row_index = getRowIndex(i); 384 buf.append("("); 385 buf.append(c); 386 buf.append(")"); 387 buf.append(row_index); 388 buf.append(" "); 389 } 390 buf.append(")"); 391 return new String (buf); 392 } 393 394 } 395 | Popular Tags |