Search in sources :

Example 56 with Savepoint

use of java.sql.Savepoint in project adempiere by adempiere.

the class Migrate method dropClient.

/**
	 * remove client entries from all tables
	 *
	 * @param clientID
	 *            client to remove
	 */
private boolean dropClient(int clientID) {
    boolean result = false;
    // Do not drop system client AD-Client_ID=0
    if (clientID == s_parameters.SYSTEMCLIENTID)
        return result;
    // list of none-AD tables in which system client data is to be preserved
    // (for example C_UOM, C_Region)
    // use UPPERCASE table tames
    ArrayList<String> tablesToPreserve = new ArrayList<String>();
    Collections.addAll(tablesToPreserve, "C_UOM", "C_UOM_CONVERSION", "C_REGION");
    String clientName = m_target.getSystemClients().get(clientID);
    s_logger.log(Level.FINE, "dropClient", new Object[] { m_objectType, clientName, m_direction });
    // iterate through all tables
    Savepoint sp = m_target.setSavepoint(clientName);
    Vector<String> v = new Vector<String>(m_targetMap.keySet());
    java.util.Collections.sort(v);
    for (Iterator<String> it = v.iterator(); it.hasNext(); ) {
        String key = it.next();
        DBObject obj = m_targetMap.get(key);
        // but only use those where an AD_Client_ID field exists.
        HashMap<Integer, DBObjectDefinition> columns = obj.getContents();
        for (Iterator<Integer> it2 = columns.keySet().iterator(); it2.hasNext(); ) {
            int key2 = it2.next();
            DBObject_Table_Column col = (DBObject_Table_Column) columns.get(key2);
            if (col.getName().equalsIgnoreCase("AD_Client_ID")) {
                String vendor = m_target.getVendor();
                String catalog = m_target.getCatalog();
                String schema = m_target.getSchema();
                String table = col.getTable();
                String whereClause = new StringBuffer("AD_Client_ID = ").append(clientID).toString();
                Statement stmt = m_target.setStatement();
                String sqlCommand = s_dbEngine.sql_deleteByCondition(vendor, catalog, schema, table, whereClause);
                Integer sqlResult = m_target.executeUpdate(stmt, sqlCommand, false, false);
                if (sqlResult != null) {
                    logDropDetail(sqlResult, null);
                    result = true;
                }
                m_target.releaseStatement(stmt);
            }
        }
    }
    m_target.releaseSavepoint(sp);
    return result;
}
Also used : Statement(java.sql.Statement) ArrayList(java.util.ArrayList) Savepoint(java.sql.Savepoint) Savepoint(java.sql.Savepoint) Vector(java.util.Vector)

Example 57 with Savepoint

use of java.sql.Savepoint in project adempiere by adempiere.

the class DBObject method update.

/**
	 * update this object
	 * @param sourceObj the object to use as template
	 * @return whether or not the object was successfully updated
	 */
public boolean update(DBObject sourceObj) {
    s_logger.log(Level.FINE, "updateThisObject", new Object[] { getObjectType(), m_name, m_parent.getDirection() });
    // remember savepoint for rollback
    Savepoint sp = m_parent.setSavepoint("update object");
    // update the object
    boolean result = m_interface.updateObject(s_parameters, s_logger, s_dbEngine, m_parent, m_name, m_headers, m_contents, sourceObj);
    // release savepoint
    m_parent.releaseSavepoint(sp);
    return result;
}
Also used : Savepoint(java.sql.Savepoint)

Example 58 with Savepoint

use of java.sql.Savepoint in project adempiere by adempiere.

the class DBObject method create.

/** 
	 * create this object
	 * @param db database in which to create this object
	 * @return whether or not the object was successfully created 
	 */
public boolean create(DBConnection db) {
    s_logger.log(Level.FINE, "createThisObject", new Object[] { getObjectType(), m_name, db.getDirection() });
    // remember savepoint for rollback
    Savepoint sp = db.setSavepoint("create object");
    // create the object
    boolean result = m_interface.createObject(s_parameters, s_logger, s_dbEngine, db, m_name, m_headers, m_contents);
    // release savepoint
    db.releaseSavepoint(sp);
    return result;
}
Also used : Savepoint(java.sql.Savepoint)

Example 59 with Savepoint

use of java.sql.Savepoint in project hive by apache.

the class TxnHandler method commitTxn.

/**
 * Concurrency/isolation notes:
 * This is mutexed with {@link #openTxns(OpenTxnRequest)} and other {@link #commitTxn(CommitTxnRequest)}
 * operations using select4update on NEXT_TXN_ID.  Also, mutexes on TXNX table for specific txnid:X
 * see more notes below.
 * In order to prevent lost updates, we need to determine if any 2 transactions overlap.  Each txn
 * is viewed as an interval [M,N]. M is the txnid and N is taken from the same NEXT_TXN_ID sequence
 * so that we can compare commit time of txn T with start time of txn S.  This sequence can be thought of
 * as a logical time counter.  If S.commitTime < T.startTime, T and S do NOT overlap.
 *
 * Motivating example:
 * Suppose we have multi-statment transactions T and S both of which are attempting x = x + 1
 * In order to prevent lost update problem, the the non-overlapping txns must lock in the snapshot
 * that they read appropriately.  In particular, if txns do not overlap, then one follows the other
 * (assumig they write the same entity), and thus the 2nd must see changes of the 1st.  We ensure
 * this by locking in snapshot after
 * {@link #openTxns(OpenTxnRequest)} call is made (see org.apache.hadoop.hive.ql.Driver.acquireLocksAndOpenTxn)
 * and mutexing openTxn() with commit().  In other words, once a S.commit() starts we must ensure
 * that txn T which will be considered a later txn, locks in a snapshot that includes the result
 * of S's commit (assuming no other txns).
 * As a counter example, suppose we have S[3,3] and T[4,4] (commitId=txnid means no other transactions
 * were running in parallel).  If T and S both locked in the same snapshot (for example commit of
 * txnid:2, which is possible if commitTxn() and openTxnx() is not mutexed)
 * 'x' would be updated to the same value by both, i.e. lost update.
 */
@Override
@RetrySemantics.Idempotent("No-op if already committed")
public void commitTxn(CommitTxnRequest rqst) throws NoSuchTxnException, TxnAbortedException, MetaException {
    long txnid = rqst.getTxnid();
    try {
        Connection dbConn = null;
        Statement stmt = null;
        ResultSet lockHandle = null;
        ResultSet commitIdRs = null, rs;
        try {
            lockInternal();
            dbConn = getDbConn(Connection.TRANSACTION_READ_COMMITTED);
            stmt = dbConn.createStatement();
            /**
             * Runs at READ_COMMITTED with S4U on TXNS row for "txnid".  S4U ensures that no other
             * operation can change this txn (such acquiring locks). While lock() and commitTxn()
             * should not normally run concurrently (for same txn) but could due to bugs in the client
             * which could then corrupt internal transaction manager state.  Also competes with abortTxn().
             */
            lockHandle = lockTransactionRecord(stmt, txnid, TXN_OPEN);
            if (lockHandle == null) {
                // if here, txn was not found (in expected state)
                TxnStatus actualTxnStatus = findTxnState(txnid, stmt);
                if (actualTxnStatus == TxnStatus.COMMITTED) {
                    /**
                     * This makes the operation idempotent
                     * (assume that this is most likely due to retry logic)
                     */
                    LOG.info("Nth commitTxn(" + JavaUtils.txnIdToString(txnid) + ") msg");
                    return;
                }
                raiseTxnUnexpectedState(actualTxnStatus, txnid);
                shouldNeverHappen(txnid);
            // dbConn is rolled back in finally{}
            }
            String conflictSQLSuffix = "from TXN_COMPONENTS where tc_txnid=" + txnid + " and tc_operation_type IN(" + quoteChar(OpertaionType.UPDATE.sqlConst) + "," + quoteChar(OpertaionType.DELETE.sqlConst) + ")";
            rs = stmt.executeQuery(sqlGenerator.addLimitClause(1, "tc_operation_type " + conflictSQLSuffix));
            if (rs.next()) {
                close(rs);
                // if here it means currently committing txn performed update/delete and we should check WW conflict
                /**
                 * This S4U will mutex with other commitTxn() and openTxns().
                 * -1 below makes txn intervals look like [3,3] [4,4] if all txns are serial
                 * Note: it's possible to have several txns have the same commit id.  Suppose 3 txns start
                 * at the same time and no new txns start until all 3 commit.
                 * We could've incremented the sequence for commitId is well but it doesn't add anything functionally.
                 */
                commitIdRs = stmt.executeQuery(sqlGenerator.addForUpdateClause("select ntxn_next - 1 from NEXT_TXN_ID"));
                if (!commitIdRs.next()) {
                    throw new IllegalStateException("No rows found in NEXT_TXN_ID");
                }
                long commitId = commitIdRs.getLong(1);
                Savepoint undoWriteSetForCurrentTxn = dbConn.setSavepoint();
                /**
                 * "select distinct" is used below because
                 * 1. once we get to multi-statement txns, we only care to record that something was updated once
                 * 2. if {@link #addDynamicPartitions(AddDynamicPartitions)} is retried by caller it my create
                 *  duplicate entries in TXN_COMPONENTS
                 * but we want to add a PK on WRITE_SET which won't have unique rows w/o this distinct
                 * even if it includes all of it's columns
                 */
                int numCompsWritten = stmt.executeUpdate("insert into WRITE_SET (ws_database, ws_table, ws_partition, ws_txnid, ws_commit_id, ws_operation_type)" + " select distinct tc_database, tc_table, tc_partition, tc_txnid, " + commitId + ", tc_operation_type " + conflictSQLSuffix);
                /**
                 * see if there are any overlapping txns wrote the same element, i.e. have a conflict
                 * Since entire commit operation is mutexed wrt other start/commit ops,
                 * committed.ws_commit_id <= current.ws_commit_id for all txns
                 * thus if committed.ws_commit_id < current.ws_txnid, transactions do NOT overlap
                 * For example, [17,20] is committed, [6,80] is being committed right now - these overlap
                 * [17,20] committed and [21,21] committing now - these do not overlap.
                 * [17,18] committed and [18,19] committing now - these overlap  (here 18 started while 17 was still running)
                 */
                rs = stmt.executeQuery(sqlGenerator.addLimitClause(1, "committed.ws_txnid, committed.ws_commit_id, committed.ws_database," + "committed.ws_table, committed.ws_partition, cur.ws_commit_id cur_ws_commit_id, " + "cur.ws_operation_type cur_op, committed.ws_operation_type committed_op " + "from WRITE_SET committed INNER JOIN WRITE_SET cur " + "ON committed.ws_database=cur.ws_database and committed.ws_table=cur.ws_table " + // have entries with partition key and w/o
                "and (committed.ws_partition=cur.ws_partition or (committed.ws_partition is null and cur.ws_partition is null)) " + // txns overlap; could replace ws_txnid
                "where cur.ws_txnid <= committed.ws_commit_id" + // with txnid, though any decent DB should infer this
                " and cur.ws_txnid=" + // make sure RHS of join only has rows we just inserted as
                txnid + // part of this commitTxn() op
                " and committed.ws_txnid <> " + // and LHS only has committed txns
                txnid + // U+U and U+D is a conflict but D+D is not and we don't currently track I in WRITE_SET at all
                " and (committed.ws_operation_type=" + quoteChar(OpertaionType.UPDATE.sqlConst) + " OR cur.ws_operation_type=" + quoteChar(OpertaionType.UPDATE.sqlConst) + ")"));
                if (rs.next()) {
                    // found a conflict
                    String committedTxn = "[" + JavaUtils.txnIdToString(rs.getLong(1)) + "," + rs.getLong(2) + "]";
                    StringBuilder resource = new StringBuilder(rs.getString(3)).append("/").append(rs.getString(4));
                    String partitionName = rs.getString(5);
                    if (partitionName != null) {
                        resource.append('/').append(partitionName);
                    }
                    String msg = "Aborting [" + JavaUtils.txnIdToString(txnid) + "," + rs.getLong(6) + "]" + " due to a write conflict on " + resource + " committed by " + committedTxn + " " + rs.getString(7) + "/" + rs.getString(8);
                    close(rs);
                    // remove WRITE_SET info for current txn since it's about to abort
                    dbConn.rollback(undoWriteSetForCurrentTxn);
                    LOG.info(msg);
                    // todo: should make abortTxns() write something into TXNS.TXN_META_INFO about this
                    if (abortTxns(dbConn, Collections.singletonList(txnid), true) != 1) {
                        throw new IllegalStateException(msg + " FAILED!");
                    }
                    dbConn.commit();
                    close(null, stmt, dbConn);
                    throw new TxnAbortedException(msg);
                } else {
                // no conflicting operations, proceed with the rest of commit sequence
                }
            } else {
            /**
             * current txn didn't update/delete anything (may have inserted), so just proceed with commit
             *
             * We only care about commit id for write txns, so for RO (when supported) txns we don't
             * have to mutex on NEXT_TXN_ID.
             * Consider: if RO txn is after a W txn, then RO's openTxns() will be mutexed with W's
             * commitTxn() because both do S4U on NEXT_TXN_ID and thus RO will see result of W txn.
             * If RO < W, then there is no reads-from relationship.
             */
            }
            // Move the record from txn_components into completed_txn_components so that the compactor
            // knows where to look to compact.
            String s = "insert into COMPLETED_TXN_COMPONENTS (ctc_txnid, ctc_database, " + "ctc_table, ctc_partition, ctc_writeid) select tc_txnid, tc_database, tc_table, " + "tc_partition, tc_writeid from TXN_COMPONENTS where tc_txnid = " + txnid;
            LOG.debug("Going to execute insert <" + s + ">");
            int modCount = 0;
            if ((modCount = stmt.executeUpdate(s)) < 1) {
                // this can be reasonable for an empty txn START/COMMIT or read-only txn
                // also an IUD with DP that didn't match any rows.
                LOG.info("Expected to move at least one record from txn_components to " + "completed_txn_components when committing txn! " + JavaUtils.txnIdToString(txnid));
            }
            s = "delete from TXN_COMPONENTS where tc_txnid = " + txnid;
            LOG.debug("Going to execute update <" + s + ">");
            modCount = stmt.executeUpdate(s);
            s = "delete from HIVE_LOCKS where hl_txnid = " + txnid;
            LOG.debug("Going to execute update <" + s + ">");
            modCount = stmt.executeUpdate(s);
            s = "delete from TXNS where txn_id = " + txnid;
            LOG.debug("Going to execute update <" + s + ">");
            modCount = stmt.executeUpdate(s);
            LOG.debug("Going to commit");
            dbConn.commit();
            // Update registry with modifications
            s = "select ctc_database, ctc_table, ctc_timestamp from COMPLETED_TXN_COMPONENTS where ctc_txnid = " + txnid;
            rs = stmt.executeQuery(s);
            if (rs.next()) {
                LOG.debug("Going to register table modification in invalidation cache <" + s + ">");
                MaterializationsInvalidationCache.get().notifyTableModification(rs.getString(1), rs.getString(2), txnid, rs.getTimestamp(3, Calendar.getInstance(TimeZone.getTimeZone("UTC"))).getTime());
            }
            close(rs);
            dbConn.commit();
        } catch (SQLException e) {
            LOG.debug("Going to rollback");
            rollbackDBConn(dbConn);
            checkRetryable(dbConn, e, "commitTxn(" + rqst + ")");
            throw new MetaException("Unable to update transaction database " + StringUtils.stringifyException(e));
        } finally {
            close(commitIdRs);
            close(lockHandle, stmt, dbConn);
            unlockInternal();
        }
    } catch (RetryException e) {
        commitTxn(rqst);
    }
}
Also used : SQLException(java.sql.SQLException) Statement(java.sql.Statement) Connection(java.sql.Connection) Savepoint(java.sql.Savepoint) Savepoint(java.sql.Savepoint) TxnAbortedException(org.apache.hadoop.hive.metastore.api.TxnAbortedException) ResultSet(java.sql.ResultSet) MetaException(org.apache.hadoop.hive.metastore.api.MetaException)

Example 60 with Savepoint

use of java.sql.Savepoint in project jdbc-shards by wplatform.

the class JdbcConnection method setSavepoint.

/**
 * Creates a new unnamed savepoint.
 *
 * @return the new savepoint
 */
@Override
public Savepoint setSavepoint() throws SQLException {
    try {
        int id = getNextId(TraceObject.SAVEPOINT);
        if (isDebugEnabled()) {
            debugCodeAssign("Savepoint", TraceObject.SAVEPOINT, id, "setSavepoint()");
        }
        checkClosed();
        CommandInterface set = prepareCommand("SAVEPOINT " + JdbcSavepoint.getName(null, savepointId), Integer.MAX_VALUE);
        set.executeUpdate();
        JdbcSavepoint savepoint = new JdbcSavepoint(this, savepointId, null, trace, id);
        savepointId++;
        return savepoint;
    } catch (Exception e) {
        throw logAndConvert(e);
    }
}
Also used : CommandInterface(com.wplatform.ddal.command.CommandInterface) Savepoint(java.sql.Savepoint) SQLClientInfoException(java.sql.SQLClientInfoException) SQLException(java.sql.SQLException) DbException(com.wplatform.ddal.message.DbException)

Aggregations

Savepoint (java.sql.Savepoint)62 SQLException (java.sql.SQLException)20 Statement (java.sql.Statement)20 Connection (java.sql.Connection)17 ResultSet (java.sql.ResultSet)13 Vector (java.util.Vector)11 ArrayList (java.util.ArrayList)10 Test (org.junit.Test)9 DatabaseMetaData (java.sql.DatabaseMetaData)6 PreparedStatement (java.sql.PreparedStatement)6 TransactionStatus (org.springframework.transaction.TransactionStatus)6 TransactionCallbackWithoutResult (org.springframework.transaction.support.TransactionCallbackWithoutResult)6 TransactionTemplate (org.springframework.transaction.support.TransactionTemplate)6 SQLClientInfoException (java.sql.SQLClientInfoException)5 HashMap (java.util.HashMap)5 SQLFeatureNotSupportedException (java.sql.SQLFeatureNotSupportedException)4 AdempiereException (org.adempiere.exceptions.AdempiereException)3 FilterChainImpl (com.alibaba.druid.filter.FilterChainImpl)2 CommandInterface (com.wplatform.ddal.command.CommandInterface)2 DbException (com.wplatform.ddal.message.DbException)2