1 24 package com.lutris.appserver.server.sql.standard; 25 26 import com.lutris.appserver.server.sql.*; 27 28 import java.util.*; 29 30 import com.lutris.dods.builder.generator.dataobject.GenericDO; 31 import com.lutris.dods.builder.generator.query.DataObjectException; 32 import com.lutris.logging.Logger; 33 import java.sql.PreparedStatement ; 34 import java.sql.SQLException ; 35 import org.enhydra.dods.DODS; 36 import org.enhydra.dods.cache.DOCache; 37 import org.enhydra.dods.cache.TransactionCacheImpl; 38 import org.enhydra.dods.cache.Wrapper; 39 import org.enhydra.dods.exceptions.CacheObjectException; 40 41 49 public class StandardDBTransaction implements CachedDBTransaction { 50 protected int id; 52 protected static int nextId; 54 protected DBConnection conn; 56 protected boolean released = false; 58 protected boolean _preventCacheQueries = false; 59 protected Vector vecAlreadyHidden = new Vector(); 60 protected Vector vecExecutedTransaction = new Vector(); 61 protected Vector vecSortedTransaction = new Vector(); 63 protected HashMap hmpObjectTransaction = new HashMap(); 64 protected Transaction[] trans = {}; 69 protected int[] transAction = {}; 72 protected int transIdx = 0; 74 protected int dbLockCounter = 0; 76 protected final int SIZE_DELTA = 10; 78 protected final int CACHE_SIZE = -1; 80 81 protected final int COMPLEX_QUERY_CACHE_SIZE = 0; 83 84 protected final int SIMPLE_QUERY_CACHE_SIZE = 0; 86 87 protected DOCache cache = null; 89 90 protected Vector deletedRefs = null; 92 93 96 protected static final int INSERT = 1; 98 protected static final int UPDATE = 2; 99 protected static final int DELETE = 3; 100 101 protected boolean isTransactionCaches; 102 protected boolean isAutoWrite = false; 103 protected boolean sqlBatch; 104 protected boolean firstWrite = true; 105 106 114 protected StandardDBTransaction(DBConnection conn) throws SQLException { 115 try { 116 firstWrite=true; 117 id = nextId++; 118 logDebug("new instance"); 119 this.conn = conn; 120 this.conn.setAutoCommit(false); 121 setDatabaseName(conn.getDatabaseName()); 122 readConfigValues(); 123 if (isTransactionCaches) { 124 cache = new TransactionCacheImpl(SIMPLE_QUERY_CACHE_SIZE, 125 COMPLEX_QUERY_CACHE_SIZE); 126 } 127 } catch (SQLException sqlExcept) { 128 this.conn.handleException(sqlExcept); 129 this.conn.release(); 130 throw sqlExcept; 131 } catch (CacheObjectException cacheExcept) { 132 DODS.getLogChannel().write(Logger.ERROR, 133 "Error during transacion cache initialization"); 134 } 135 } 136 137 141 protected StandardDBTransaction(){} 142 143 144 152 public synchronized Transaction getDO(Transaction transaction) { 153 return getDO(transaction, NONE); 154 } 155 156 167 public synchronized Transaction getDO(Transaction transaction, int action) { 168 CoreDO foundDO = null; 169 170 if (transaction instanceof CoreDO) { 171 String strOID = ((CoreDO) transaction).get_OId().toString(); 172 173 if (this.hmpObjectTransaction.containsKey(strOID)) { 175 if (action == NONE 176 || ((DOAction) this.hmpObjectTransaction.get(strOID)).getAction() 177 == action) { 178 foundDO = (CoreDO) ((DOAction) this.hmpObjectTransaction.get(strOID)).getDO(); 179 } 180 } 181 } 182 return foundDO; 183 } 184 protected static final int NONE = 0; 186 195 private synchronized void add(Transaction transaction, int action) { 197 if (transaction instanceof CoreDO) { 198 String strOID = ((CoreDO) transaction).get_OId().toString(); 199 int iDOAction = NONE; 200 201 if (aggregateModifications && this.vecSortedTransaction.size() > 0) { 202 DOAction doa = (DOAction) this.vecSortedTransaction.lastElement(); 203 204 if (((CoreDO) doa.getDO()).get_OId().toString().equals(strOID)) { 205 iDOAction = ((DOAction) this.vecSortedTransaction.lastElement()).getAction(); 206 if (iDOAction == UPDATE 207 && (action == INSERT || action == UPDATE)) { 208 return; 209 } 210 if (iDOAction == INSERT 211 && (action == INSERT || action == UPDATE)) { 212 return; 213 } 214 if (iDOAction == DELETE && action == DELETE) { 215 return; 216 } 217 } 218 } 219 if (isAutoWrite && this.vecSortedTransaction.size() > 0) { 220 try { 221 write(); 222 } catch (SQLException sqle) { 223 sqle.printStackTrace(); 224 } 226 } 227 DOAction objDOAction = new DOAction(transaction, action); 228 229 this.hmpObjectTransaction.put(strOID, objDOAction); 230 this.vecSortedTransaction.add(objDOAction); 231 } 232 } 233 234 240 public void update(Transaction transaction) { 241 add(transaction, UPDATE); 242 aggregateModifications = true; 243 } 244 245 251 public void delete(Transaction transaction) { 252 add(transaction, DELETE); 261 aggregateModifications = true; 262 } 263 264 270 public void insert(Transaction transaction) { 271 add(transaction, INSERT); 272 aggregateModifications = true; 273 } 274 275 284 public void commit() throws SQLException , DBRowUpdateException { 285 int retryCount = lockRetryCount; 286 long wrapperHandle = 0; 287 Vector vecDOclass = new Vector(); 288 289 logDebug("commit"); 290 validate(); 291 if (!wasReadOnly()) { 292 try { 295 conn.incrRequestCount(); write(); 297 while (0 == (wrapperHandle = Wrapper.getInstance().lock())) { 299 try { 300 Thread.sleep(lockWaitTime); 301 } catch (InterruptedException ie) {} 302 if (retryCount-- == 0) { 303 throw new SQLException ("Can't wait anymore."); 304 } 305 } 306 for (Enumeration e = vecExecutedTransaction.elements(); e.hasMoreElements();) { 308 CoreDO cdo = (CoreDO) ((DOAction) e.nextElement()).getDO(); 309 Class doClass = cdo.getClass(); 310 311 if (!vecDOclass.contains(doClass)) { 312 vecDOclass.add(doClass); 313 } 314 if (!vecAlreadyHidden.contains(cdo)) { 315 cdo.makeInvisible(); 316 vecAlreadyHidden.add(cdo); 317 } 318 } 319 Wrapper.getInstance().makeSimpleComplexQCachesInvisible(vecDOclass); 320 Wrapper.getInstance().makeMultiJoinQCachesInvisible(); Wrapper.getInstance().unlock(wrapperHandle); 323 wrapperHandle = 0; 324 conn.commit(); 325 transactionNotify(true); 327 Wrapper.getInstance().removeAllMultiJoinQueries(); } catch (SQLException sqlExcept) { 329 handleException(sqlExcept); 330 rollback(); 331 throw sqlExcept; 332 } finally { 333 if (retryCount >= 0) { 334 while (0 == (wrapperHandle = Wrapper.getInstance().lock())) { 335 try { 336 Thread.sleep(lockWaitTime); 337 } catch (InterruptedException ie) {} 338 if (--retryCount == 0) { 339 logDebug("spent " + lockRetryCount + " times " 340 + lockWaitTime 341 + "miliseconds, but musn't give up."); 342 retryCount = lockRetryCount; 343 } 344 } 345 for (Enumeration e = vecAlreadyHidden.elements(); e.hasMoreElements();) { 346 ((CoreDO) e.nextElement()).makeVisible(); 347 } 348 Wrapper.getInstance().makeSimpleComplexQCachesVisible(vecDOclass); 349 Wrapper.getInstance().makeMultiJoinQCachesVisible(); Wrapper.getInstance().unlock(wrapperHandle); 351 } 352 this.hmpObjectTransaction = new HashMap(); 354 this.vecSortedTransaction = new Vector(); 355 this.vecExecutedTransaction = new Vector(); 356 this.vecAlreadyHidden = new Vector(); 357 _preventCacheQueries = false; 358 } 359 } else { 360 logDebug("Nothing to write."); 363 } 364 } 365 366 375 public void rollback() throws SQLException { 376 try { 377 logDebug("rollback"); 378 validate(); 379 conn.rollback(); 380 for (int iCounter = 0; iCounter < this.vecSortedTransaction.size(); iCounter++) { 382 try { 383 DOAction objDOAction = (DOAction) this.vecSortedTransaction.get(iCounter); 384 385 ((CoreDO) objDOAction.getDO()).refresh(); 386 } catch (DataObjectException dataExept) { 387 if (dataExept.getMessage().indexOf("DO not found for id") 389 != -1) { DOAction objDOAction = (DOAction) this.vecSortedTransaction.get(iCounter); 391 392 ((CoreDO) objDOAction.getDO()).evict(); 393 } else { 394 SQLException g = new SQLException ("INTERNAL ERROR: unexpected DataObjectException"); 395 throw g; 396 } 397 } 398 } 399 } catch (SQLException sqlExcept) { 400 handleException(sqlExcept); 401 throw sqlExcept; 402 } 403 finally { 404 transactionNotify(false); 406 this.hmpObjectTransaction = new HashMap(); 408 this.vecSortedTransaction = new Vector(); 409 } 413 } 414 415 423 private synchronized void transactionNotify(boolean succeeded) { 424 for (int iCounter = 0; iCounter < this.vecExecutedTransaction.size(); iCounter++) { 425 DOAction objDOAction = (DOAction) this.vecExecutedTransaction.get(iCounter); 426 427 switch (objDOAction.getAction()) { 428 case INSERT: 429 objDOAction.getDO().finalizeInsert(succeeded); 430 break; 431 432 case UPDATE: 433 objDOAction.getDO().finalizeUpdate(succeeded); 434 break; 435 436 case DELETE: 437 objDOAction.getDO().finalizeDelete(succeeded); 438 break; 439 } 440 } 441 } 442 443 452 public synchronized void release() { 453 try { 454 logDebug("release"); 455 if (!released) { 456 if (vecExecutedTransaction.size() > 0) { 457 rollback(); 458 } 459 conn.reset(); 460 } 461 } catch (SQLException sqlExcept) { 462 handleException(sqlExcept); 463 } 464 finally { 465 if(conn!=null) 466 conn.release(); 467 conn = null; 468 released = true; 469 cache = null; 470 this.hmpObjectTransaction = new HashMap(); this.vecSortedTransaction = new Vector(); 472 this.vecExecutedTransaction = new Vector(); 473 } 474 } 475 476 484 public synchronized boolean handleException(SQLException e) { 485 logDebug("handle exception"); 486 return conn.handleException(e); 487 } 488 489 497 protected void validate() throws SQLException { 498 if (released) { 499 throw new SQLException ("Cannot access DBTransaction object " 500 + "once it has been released."); 501 } 502 } 503 504 505 512 public boolean isReleased() { 513 return released; 514 } 515 516 520 protected void finalize() { 521 if (!released) { 522 release(); 523 } 524 } 525 526 532 protected void logDebug(String str) { 533 if (DatabaseManager.debug) { 534 DODS.getLogChannel().write(Logger.DEBUG, "DBTransaction[" + id + "]: " + str); 535 } 536 } 537 protected class DOAction { 538 private Transaction transDO; 539 private int iAction; 540 public DOAction(Transaction transDOIn, int iActionIn) { 541 this.transDO = transDOIn; 542 this.iAction = iActionIn; 543 } 544 545 public Transaction getDO() { 546 return this.transDO; 547 } 548 549 public int getAction() { 550 return this.iAction; 551 } 552 553 public void setAction(int action) { 554 this.iAction = action; 555 } 556 public boolean equals(Object o) { 557 return o instanceof DOAction 558 && iAction == ((DOAction)o).iAction 559 && transDO.equals(((DOAction)o).transDO); 560 } 561 } 562 563 566 protected String databaseName; 567 568 573 public String getDatabaseName() { 574 return databaseName; 575 } 576 577 582 public void setDatabaseName(String dbName) { 583 databaseName = dbName; 584 } 585 586 591 public CoreDO[] getDOs() { 592 return (CoreDO[]) vecSortedTransaction.toArray(); 593 } 594 595 598 public void saveDirtyDOs() { 599 throw new RuntimeException ("NOT implemented, yet!"); 600 } 601 602 607 public void write() throws SQLException , DBRowUpdateException { 608 logDebug("write"); 609 validate(); 610 if (firstWrite){ 612 firstWrite=false; 613 if (conn.getConnection().isClosed()){ 614 logDebug("Write failed, connection are closed by driver"); 615 throw new SQLException ("Write failed, connection are closed by driver"); 616 } 617 } 618 try { 619 PreparedStatement stmt = null; 620 ArrayList batch = new ArrayList(); 621 for (int iCounter = 0; iCounter < this.vecSortedTransaction.size();) { 622 DOAction objDOAction = (DOAction) this.vecSortedTransaction.get(iCounter); 623 int action = objDOAction.getAction(); 624 CoreDO aDO = (CoreDO) objDOAction.getDO(); 625 626 if (this.vecSortedTransaction.size() > 1) { 627 DOAction objNextDOAction = (DOAction) this.vecSortedTransaction 628 .get(1 + iCounter); 629 630 if (DELETE == objNextDOAction.getAction() 631 && aDO.get_OId().equals(((CoreDO) objNextDOAction.getDO()).get_OId())) { 632 if (!aDO.isPersistent()) { 633 this.vecSortedTransaction.remove(objNextDOAction); 634 } 635 this.vecSortedTransaction.remove(objDOAction); 636 continue; 637 } 638 } 639 switch (action) { 640 case INSERT: 641 if (isSQLbatch()) { 642 if (!(aDO instanceof GenericDO) 643 || ((GenericDO)aDO).isDirty()) { 644 stmt = (aDO.isPersistent()) 645 ? aDO.getUpdateStatement(conn) 646 : aDO.getInsertStatement(conn); 647 stmt.addBatch(); 648 aDO.setPersistent(true); 649 if (!batch.contains(stmt)) { 650 batch.add(stmt); 651 } 652 } 653 } else 654 aDO.executeInsert(conn); 655 break; 656 657 case UPDATE: 658 if (isSQLbatch()) { 659 if (!(aDO instanceof GenericDO) 660 || ((GenericDO)aDO).isDirty()) { 661 stmt = aDO.getUpdateStatement(conn); 662 stmt.addBatch(); 663 if (!batch.contains(stmt)) { 664 batch.add(stmt); 665 } 666 } 667 } else 668 aDO.executeUpdate(conn); 669 break; 670 671 case DELETE: 672 if (isSQLbatch()) { 673 stmt = aDO.getDeleteStatement(conn); 674 stmt.addBatch(); 675 if (!batch.contains(stmt)) 676 batch.add(stmt); 677 } else 678 aDO.executeDelete(conn); 679 break; 680 } 681 _preventCacheQueries = true; 682 683 this.vecExecutedTransaction.add(objDOAction); 684 this.vecSortedTransaction.remove(iCounter); 685 } 686 if (isSQLbatch()) { 687 for (Iterator iter = batch.iterator(); 689 iter.hasNext();) { 690 PreparedStatement element = (PreparedStatement )iter.next(); 691 int[] affected = element.executeBatch(); 692 element.clearBatch(); 693 for (int _i = 0; _i < affected.length; ++_i) { 694 if (affected[_i] <= 0) 695 throw new DBRowUpdateException("batch failed for " 696 + element 697 +" returned " 698 +affected[_i]); 699 } 700 } 701 } 702 } catch (SQLException e) { 703 logDebug("Write failed, there are " + vecSortedTransaction.size() 704 + " DOs unwritten."); 705 throw e; 706 } 707 } 708 709 714 public DOCache getTransactionCache() { 715 return cache; 716 } 717 718 723 private void setTransactionCache(DOCache transCache) { 724 cache = transCache; 725 } 726 private long lockWaitTime; 727 private int lockRetryCount; 728 729 732 public Vector getDeletedDOs() { 733 734 return deletedRefs; 735 } 736 737 740 public void addDeletedDO(CoreDO DO) { 741 742 if (deletedRefs == null) { 743 deletedRefs = new Vector(); 744 } 745 String handle = null; 746 747 if (DO.get_OId() != null) { 748 handle = getDatabaseName() + "." + DO.get_OId(); 749 deletedRefs.addElement(handle); 750 } 751 } 752 753 756 public void resetDeletedDOs() { 757 if (deletedRefs != null) { 758 deletedRefs = new Vector(); 759 } 760 } 761 762 public void lockDO(Transaction cdo) throws SQLException { 763 ((CoreDO) cdo).executeLockingStatement(conn); 764 } 765 766 770 public boolean preventCacheQueries() { 771 return _preventCacheQueries; 772 } 773 774 781 public DBQuery createQuery() throws SQLException { 782 StandardDBQuery sdbq = new StandardDBQuery(conn); 783 784 sdbq.setReleaseConnection(false); 785 return sdbq; 786 } 787 protected boolean aggregateModifications = true; 788 789 792 public void dontAggregateDOModifications() { 793 aggregateModifications = false; 794 } 795 796 803 protected void readConfigValues() { 804 try { 805 isTransactionCaches = ((StandardLogicalDatabase) (DODS.getDatabaseManager().findLogicalDatabase(getDatabaseName()))).getDatabaseConfiguration().getTransactionCaches(); 806 } catch (Exception ex) { 807 isTransactionCaches = ((StandardDatabaseManager) (DODS.getDatabaseManager())).getDatabaseManagerConfiguration().getTransactionCaches(); 808 } 809 try { 810 lockWaitTime = ((StandardLogicalDatabase) (DODS.getDatabaseManager().findLogicalDatabase(getDatabaseName()))).getDatabaseConfiguration().getDeadlockWaitTime(); 811 } catch (Exception ex) { 812 lockWaitTime = ((StandardDatabaseManager) (DODS.getDatabaseManager())).getDatabaseManagerConfiguration().getDeadlockWaitTime(); 813 } 814 try { 815 lockRetryCount = ((StandardLogicalDatabase) (DODS.getDatabaseManager().findLogicalDatabase(getDatabaseName()))).getDatabaseConfiguration().getDeadlockRetryCount(); 816 } catch (Exception ex) { 817 lockRetryCount = ((StandardDatabaseManager) (DODS.getDatabaseManager())).getDatabaseManagerConfiguration().getDeadlockRetryCount(); 818 } 819 try { 820 isAutoWrite = ((StandardLogicalDatabase) (DODS.getDatabaseManager().findLogicalDatabase(getDatabaseName()))).getDatabaseConfiguration().getAutoWrite(); 821 } catch (Exception ex) { 822 isAutoWrite = ((StandardDatabaseManager) (DODS.getDatabaseManager())).getDatabaseManagerConfiguration().getAutoWrite(); 823 } 824 try { 825 sqlBatch = ((StandardLogicalDatabase) (DODS.getDatabaseManager().findLogicalDatabase(getDatabaseName()))).getDatabaseConfiguration().isSqlBatch(); 826 } catch (Exception ex) { 827 sqlBatch = ((StandardDatabaseManager) (DODS.getDatabaseManager())).getDatabaseManagerConfiguration().isSqlBatch(); 828 } 829 } 830 831 838 public boolean getAutoWrite() { 839 return isAutoWrite; 840 } 841 public boolean isSQLbatch() { 842 return sqlBatch; 843 } 844 845 848 public boolean isFirstWrite(){ 849 return firstWrite; 850 } 851 852 853 856 public void setFirstWrite(boolean newfw){ 857 firstWrite=newfw; 858 } 859 860 public boolean wasReadOnly() { 861 return 0 == vecExecutedTransaction.size() + vecSortedTransaction.size(); 862 } 863 } 864 | Popular Tags |