1 29 30 package com.caucho.db.store; 31 32 import com.caucho.db.jdbc.ConnectionImpl; 33 import com.caucho.log.Log; 34 import com.caucho.sql.SQLExceptionWrapper; 35 import com.caucho.util.L10N; 36 import com.caucho.util.LongKeyHashMap; 37 38 import java.io.IOException ; 39 import java.sql.SQLException ; 40 import java.util.ArrayList ; 41 import java.util.Iterator ; 42 import java.util.logging.Level ; 43 import java.util.logging.Logger ; 44 45 48 public class Transaction extends StoreTransaction { 49 private static final Logger log = Log.open(Transaction.class); 50 private static final L10N L = new L10N(Transaction.class); 51 52 private static long AUTO_COMMIT_TIMEOUT = 30000L; 53 54 private boolean _isAutoCommit = true; 55 private ConnectionImpl _conn; 56 57 private ArrayList <Lock> _readLocks; 58 private ArrayList <Lock> _writeLocks; 59 60 private LongKeyHashMap<WriteBlock> _writeBlocks; 61 62 private ArrayList <Block> _updateBlocks; 63 64 private ArrayList <Inode> _deleteInodes; 66 67 private ArrayList <Inode> _addInodes; 69 70 private ArrayList <Block> _deallocateBlocks; 72 73 private boolean _isRollbackOnly; 74 private SQLException _rollbackExn; 75 76 private long _timeout = AUTO_COMMIT_TIMEOUT; 77 78 private Transaction() 79 { 80 } 81 82 public static Transaction create(ConnectionImpl conn) 83 { 84 Transaction xa = new Transaction(); 85 86 xa.init(conn); 87 88 return xa; 89 } 90 91 public static Transaction create() 92 { 93 Transaction xa = new Transaction(); 94 95 return xa; 96 } 97 98 private void init(ConnectionImpl conn) 99 { 100 _conn = conn; 101 _timeout = AUTO_COMMIT_TIMEOUT; 102 _isRollbackOnly = false; 103 _rollbackExn = null; 104 } 105 106 109 public void setTimeout(long timeout) 110 { 111 _timeout = timeout; 112 } 113 114 117 123 124 127 public boolean hasReadLock(Lock lock) 128 { 129 return _readLocks.contains(lock); 130 } 131 132 135 public boolean isAutoCommit() 136 { 137 return _isAutoCommit; 138 } 139 140 143 public void setAutoCommit(boolean autoCommit) 144 { 145 _isAutoCommit = autoCommit; 146 } 147 148 151 public void lockRead(Lock lock) 152 throws SQLException 153 { 154 if (_isRollbackOnly) { 155 if (_rollbackExn != null) 156 throw _rollbackExn; 157 else 158 throw new SQLException (L.l("can't get lock with rollback transaction")); 159 } 160 161 try { 162 if (_readLocks == null) 163 _readLocks = new ArrayList <Lock>(); 164 165 if (! _readLocks.contains(lock)) { 166 lock.lockRead(this, _timeout); 167 _readLocks.add(lock); 168 } 169 } catch (SQLException e) { 170 setRollbackOnly(e); 171 172 throw e; 173 } 174 } 175 176 177 180 public void lockReadAndWrite(Lock lock) 181 throws SQLException 182 { 183 lockWrite(lock); 184 } 185 186 189 public void lockWrite(Lock lock) 190 throws SQLException 191 { 192 if (_isRollbackOnly) { 193 if (_rollbackExn != null) 194 throw _rollbackExn; 195 else 196 throw new SQLException (L.l("can't get lock with rollback transaction")); 197 } 198 199 try { 200 if (_readLocks == null) 201 _readLocks = new ArrayList <Lock>(); 202 if (_writeLocks == null) 203 _writeLocks = new ArrayList <Lock>(); 204 205 if (_writeLocks.contains(lock)) { 206 return; 207 } 208 else if (_readLocks.contains(lock)) { 209 lock.lockWrite(this, _timeout); 210 _writeLocks.add(lock); 211 } 212 else { 213 lock.lockReadAndWrite(this, _timeout); 214 _readLocks.add(lock); 215 _writeLocks.add(lock); 216 } 217 } catch (SQLException e) { 218 setRollbackOnly(e); 219 220 throw e; 221 } 222 } 223 224 227 public void addUpdateBlock(Block block) 228 { 229 if (block == null) 230 return; 231 232 if (_updateBlocks == null) 233 _updateBlocks = new ArrayList <Block>(); 234 235 if (_updateBlocks.size() == 0 236 || _updateBlocks.get(_updateBlocks.size() - 1) != block) 237 _updateBlocks.add(block); 238 } 239 240 243 public void autoCommitRead(Lock lock) 244 throws SQLException 245 { 246 unlockRead(lock); 247 } 248 249 public void unlockRead(Lock lock) 250 throws SQLException 251 { 252 if (_readLocks.remove(lock)) 253 lock.unlockRead(); 254 } 255 256 259 public void autoCommitWrite(Lock lock) 260 throws SQLException 261 { 262 _readLocks.remove(lock); 263 264 if (_writeLocks.remove(lock)) { 265 try { 266 commit(); 267 } finally { 268 lock.unlockWrite(); 269 } 270 } 271 } 272 273 public void unlockReadAndWrite(Lock lock) 274 throws SQLException 275 { 276 _readLocks.remove(lock); 277 278 if (_writeLocks.remove(lock)) { 279 lock.unlockReadAndWrite(); 280 } 281 } 282 283 public void unlockWrite(Lock lock) 284 throws SQLException 285 { 286 if (_writeLocks.remove(lock)) { 287 lock.unlockWrite(); 288 } 289 } 290 291 294 public Block readBlock(Store store, long blockAddress) 295 throws IOException 296 { 297 long blockId = store.addressToBlockId(blockAddress); 298 299 Block block; 300 301 if (_writeBlocks != null) 302 block = _writeBlocks.get(blockId); 303 else 304 block = null; 305 306 if (block != null) 307 block.allocate(); 308 else 309 block = store.readBlock(blockId); 310 311 return block; 312 } 313 314 317 public WriteBlock getWriteBlock(long blockId) 318 { 319 if (_writeBlocks == null) 320 return null; 321 322 return _writeBlocks.get(blockId); 323 } 324 325 328 public WriteBlock createWriteBlock(Block block) 329 throws IOException 330 { 331 if (block instanceof WriteBlock) 332 return (WriteBlock) block; 333 334 WriteBlock writeBlock = getWriteBlock(block.getBlockId()); 335 336 if (writeBlock != null) { 337 block.free(); 338 writeBlock.allocate(); 339 return writeBlock; 340 } 341 342 if (isAutoCommit()) 343 writeBlock = new AutoCommitWriteBlock(block); 344 else { 345 writeBlock = new XAWriteBlock(block); 347 setBlock(writeBlock); 348 } 349 350 351 return writeBlock; 352 } 353 354 357 public Block createAutoCommitWriteBlock(Block block) 358 throws IOException 359 { 360 if (block instanceof WriteBlock) { 361 return block; 362 } 363 else { 364 WriteBlock writeBlock = getWriteBlock(block.getBlockId()); 365 366 if (writeBlock != null) { 367 block.free(); 368 writeBlock.allocate(); 369 370 return writeBlock; 371 } 372 373 writeBlock = new AutoCommitWriteBlock(block); 374 375 377 return writeBlock; 378 } 379 } 380 381 384 public Block allocateRow(Store store) 385 throws IOException 386 { 387 return store.allocateRow(); 388 } 389 390 393 public void deallocateBlock(Block block) 394 throws IOException 395 { 396 if (isAutoCommit()) 397 block.getStore().freeBlock(block.getBlockId()); 398 else { 399 if (_deallocateBlocks == null) 400 _deallocateBlocks = new ArrayList <Block>(); 401 402 _deallocateBlocks.add(block); 403 } 404 } 405 406 409 public Block createWriteBlock(Store store, long blockAddress) 410 throws IOException 411 { 412 Block block = readBlock(store, blockAddress); 413 414 return createWriteBlock(block); 415 } 416 417 420 private void setBlock(WriteBlock block) 421 { 422 424 if (_writeBlocks == null) 425 _writeBlocks = new LongKeyHashMap<WriteBlock>(8); 426 427 _writeBlocks.put(block.getBlockId(), block); 428 } 429 430 433 public void addDeleteInode(Inode inode) 434 { 435 if (_deleteInodes == null) 436 _deleteInodes = new ArrayList <Inode>(); 437 438 _deleteInodes.add(inode); 439 } 440 441 444 public void addAddInode(Inode inode) 445 { 446 if (_addInodes == null) 447 _addInodes = new ArrayList <Inode>(); 448 449 _addInodes.add(inode); 450 } 451 452 public void autoCommit() 453 throws SQLException 454 { 455 if (_isAutoCommit) { 456 ConnectionImpl conn = _conn; 457 _conn = null; 458 459 if (conn != null) { 460 conn.setTransaction(null); 461 } 462 } 463 } 464 465 public void setRollbackOnly(SQLException e) 466 { 467 if (_rollbackExn == null) 468 _rollbackExn = e; 469 470 _isRollbackOnly = true; 471 472 releaseLocks(); 473 474 _writeBlocks = null; 476 } 477 478 public void setRollbackOnly() 479 { 480 setRollbackOnly(null); 481 } 482 483 public void commit() 484 throws SQLException 485 { 486 try { 487 writeData(); 488 } finally { 489 releaseLocks(); 490 491 close(); 492 } 493 } 494 495 public void writeData() 496 throws SQLException 497 { 498 LongKeyHashMap<WriteBlock> writeBlocks = _writeBlocks; 499 500 if (_deleteInodes != null) { 501 while (_deleteInodes.size() > 0) { 502 Inode inode = _deleteInodes.remove(0); 503 504 inode.remove(); 506 } 507 } 508 509 ArrayList <Block> updateBlocks = _updateBlocks; 510 _updateBlocks = null; 511 512 if (updateBlocks != null) { 513 while (updateBlocks.size() > 0) { 514 Block block = updateBlocks.remove(updateBlocks.size() - 1); 515 516 try { 517 block.commit(); 518 } catch (IOException e) { 519 log.log(Level.WARNING, e.toString(), e); 520 } 521 } 522 } 523 524 if (writeBlocks != null) { 525 Iterator <WriteBlock> blockIter = writeBlocks.valueIterator(); 526 527 while (blockIter.hasNext()) { 528 WriteBlock block = blockIter.next(); 529 530 try { 531 block.commit(); 532 } catch (IOException e) { 533 log.log(Level.WARNING, e.toString(), e); 534 } 535 } 536 537 } 539 540 if (_deallocateBlocks != null) { 541 while (_deallocateBlocks.size() > 0) { 542 Block block = _deallocateBlocks.remove(0); 543 544 try { 545 block.getStore().freeBlock(block.getBlockId()); 546 } catch (IOException e) { 547 throw new SQLExceptionWrapper(e); 548 } 549 } 550 } 551 } 552 553 public void rollback() 554 throws SQLException 555 { 556 releaseLocks(); 557 558 close(); 559 } 560 561 private void releaseLocks() 562 { 563 if (_writeLocks != null) { 565 for (int i = 0; i < _writeLocks.size(); i++) { 566 Lock lock = _writeLocks.get(i); 567 568 if (_readLocks != null) 569 _readLocks.remove(lock); 570 571 try { 572 lock.unlockReadAndWrite(); 573 } catch (Throwable e) { 574 log.log(Level.WARNING, e.toString(), e); 575 } 576 } 577 578 _writeLocks.clear(); 579 } 580 581 if (_readLocks != null) { 582 for (int i = 0; i < _readLocks.size(); i++) { 583 Lock lock = _readLocks.get(i); 584 585 try { 586 lock.unlockRead(); 587 } catch (Throwable e) { 588 log.log(Level.WARNING, e.toString(), e); 589 } 590 } 591 592 _readLocks.clear(); 593 } 594 } 595 596 void close() 597 { 598 LongKeyHashMap<WriteBlock> writeBlocks = _writeBlocks; 599 _writeBlocks = null; 600 601 if (writeBlocks != null) { 602 Iterator <WriteBlock> blockIter = writeBlocks.valueIterator(); 603 604 while (blockIter.hasNext()) { 605 WriteBlock block = blockIter.next(); 606 607 block.destroy(); 608 } 609 610 } 612 613 _isRollbackOnly = false; 614 _rollbackExn = null; 615 } 616 } 617 | Popular Tags |