/** * Partially roll back the current transaction. * * @param savepoint the savepoint to which should be rolled back * @param trimToSize if the list should be trimmed */ public void rollbackTo(Savepoint savepoint, boolean trimToSize) { int index = savepoint == null ? 0 : savepoint.logIndex; while (undoLog.size() > index) { UndoLogRecord entry = undoLog.getLast(); entry.undo(this); undoLog.removeLast(trimToSize); } if (transaction != null) { long savepointId = savepoint == null ? 0 : savepoint.transactionSavepoint; HashMap<String, MVTable> tableMap = database.getMvStore().getTables(); Iterator<Change> it = transaction.getChanges(savepointId); while (it.hasNext()) { Change c = it.next(); MVTable t = tableMap.get(c.mapName); if (t != null) { long key = ((ValueLong) c.key).getLong(); ValueArray value = (ValueArray) c.value; short op; Row row; if (value == null) { op = UndoLogRecord.INSERT; row = t.getRow(this, key); } else { op = UndoLogRecord.DELETE; row = new Row(value.getList(), Row.MEMORY_CALCULATE); } row.setKey(key); UndoLogRecord log = new UndoLogRecord(t, op, row); log.undo(this); } } } if (savepoints != null) { String[] names = new String[savepoints.size()]; savepoints.keySet().toArray(names); for (String name : names) { Savepoint sp = savepoints.get(name); int savepointIndex = sp.logIndex; if (savepointIndex > index) { savepoints.remove(name); } } } }
/** * Commit the current transaction. If the statement was not a data definition statement, and if * there are temporary tables that should be dropped or truncated at commit, this is done as well. * * @param ddl if the statement was a data definition statement */ public void commit(boolean ddl) { checkCommitRollback(); currentTransactionName = null; transactionStart = 0; if (transaction != null) { // increment the data mod count, so that other sessions // see the changes // TODO should not rely on locking if (locks.size() > 0) { for (int i = 0, size = locks.size(); i < size; i++) { Table t = locks.get(i); if (t instanceof MVTable) { ((MVTable) t).commit(); } } } transaction.commit(); transaction = null; } if (containsUncommitted()) { // need to commit even if rollback is not possible // (create/drop table and so on) database.commit(this); } removeTemporaryLobs(true); if (undoLog.size() > 0) { // commit the rows when using MVCC if (database.isMultiVersion()) { ArrayList<Row> rows = New.arrayList(); synchronized (database) { while (undoLog.size() > 0) { UndoLogRecord entry = undoLog.getLast(); entry.commit(); rows.add(entry.getRow()); undoLog.removeLast(false); } for (int i = 0, size = rows.size(); i < size; i++) { Row r = rows.get(i); r.commit(); } } } undoLog.clear(); } if (!ddl) { // do not clean the temp tables if the last command was a // create/drop cleanTempTables(false); if (autoCommitAtTransactionEnd) { autoCommit = true; autoCommitAtTransactionEnd = false; } } endTransaction(); }