/** * 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(); }
/** * 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 (containsUncommitted()) { // need to commit even if rollback is not possible // (create/drop table and so on) database.commit(this); } 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; } } if (unlinkLobMap != null && unlinkLobMap.size() > 0) { // need to flush the transaction log, because we can't unlink lobs if the // commit record is not written database.flush(); for (Value v : unlinkLobMap.values()) { v.unlink(); v.close(); } unlinkLobMap = null; } unlockAll(); }
/** * Add an undo log entry to this session. * * @param table the table * @param operation the operation type (see {@link UndoLogRecord}) * @param row the row */ public void log(Table table, short operation, Row row) { if (undoLogEnabled) { UndoLogRecord log = new UndoLogRecord(table, operation, row); // called _after_ the row was inserted successfully into the table, // otherwise rollback will try to rollback a not-inserted row if (SysProperties.CHECK) { int lockMode = database.getLockMode(); if (lockMode != Constants.LOCK_MODE_OFF && !database.isMultiVersion()) { String tableType = log.getTable().getTableType(); if (locks.indexOf(log.getTable()) < 0 && !Table.TABLE_LINK.equals(tableType) && !Table.EXTERNAL_TABLE_ENGINE.equals(tableType)) { DbException.throwInternalError(); } } } undoLog.add(log); } else { if (database.isMultiVersion()) { // see also UndoLogRecord.commit ArrayList<Index> indexes = table.getIndexes(); for (int i = 0, size = indexes.size(); i < size; i++) { Index index = indexes.get(i); index.commit(operation, row); } row.commit(); } } }
/** Fully roll back the current transaction. */ public void rollback() { checkCommitRollback(); currentTransactionName = null; boolean needCommit = false; if (undoLog.size() > 0) { rollbackTo(null, false); needCommit = true; } if (transaction != null) { rollbackTo(null, false); needCommit = true; // rollback stored the undo operations in the transaction // committing will end the transaction transaction.commit(); transaction = null; } if (locks.size() > 0 || needCommit) { database.commit(this); } cleanTempTables(false); if (autoCommitAtTransactionEnd) { autoCommit = true; autoCommitAtTransactionEnd = false; } endTransaction(); }
/** * Partially roll back the current transaction. * * @param index the position to which should be rolled back * @param trimToSize if the list should be trimmed */ public void rollbackTo(int index, boolean trimToSize) { while (undoLog.size() > index) { UndoLogRecord entry = undoLog.getLast(); entry.undo(this); undoLog.removeLast(trimToSize); } if (savepoints != null) { String[] names = new String[savepoints.size()]; savepoints.keySet().toArray(names); for (String name : names) { Integer savepointIndex = savepoints.get(name); if (savepointIndex.intValue() > index) { savepoints.remove(name); } } } }
/** * Create a savepoint to allow rolling back to this state. * * @return the savepoint */ public Savepoint setSavepoint() { Savepoint sp = new Savepoint(); sp.logIndex = undoLog.size(); if (database.getMvStore() != null) { sp.transactionSavepoint = getStatementSavepoint(); } return sp; }
/** * 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); } } } }
/** * Create a savepoint that is linked to the current log position. * * @param name the savepoint name */ public void addSavepoint(String name) { if (savepoints == null) { savepoints = database.newStringMap(); } Savepoint sp = new Savepoint(); sp.logIndex = undoLog.size(); if (database.getMvStore() != null) { sp.transactionSavepoint = getStatementSavepoint(); } savepoints.put(name, sp); }
public void close() { if (!closed) { try { database.checkPowerOff(); cleanTempTables(true); undoLog.clear(); database.removeSession(this); } finally { closed = true; } } }
public Value getTransactionId() { if (database.getMvStore() != null) { if (transaction == null) { return ValueNull.INSTANCE; } return ValueString.get(Long.toString(getTransaction().getId())); } if (!database.isPersistent()) { return ValueNull.INSTANCE; } if (undoLog.size() == 0) { return ValueNull.INSTANCE; } return ValueString.get(firstUncommittedLog + "-" + firstUncommittedPos + "-" + id); }
private void unlockAll() { if (SysProperties.CHECK) { if (undoLog.size() > 0) { DbException.throwInternalError(); } } if (locks.size() > 0) { // don't use the enhanced for loop to save memory for (int i = 0, size = locks.size(); i < size; i++) { Table t = locks.get(i); t.unlock(this); } locks.clear(); } savepoints = null; sessionStateChanged = true; }
/** Fully roll back the current transaction. */ public void rollback() { checkCommitRollback(); currentTransactionName = null; boolean needCommit = false; if (undoLog.size() > 0) { rollbackTo(0, false); needCommit = true; } if (locks.size() > 0 || needCommit) { database.commit(this); } cleanTempTables(false); unlockAll(); if (autoCommitAtTransactionEnd) { autoCommit = true; autoCommitAtTransactionEnd = false; } }
public int getUndoLogPos() { return undoLog.size(); }
public Value getTransactionId() { if (undoLog.size() == 0 || !database.isPersistent()) { return ValueNull.INSTANCE; } return ValueString.get(firstUncommittedLog + "-" + firstUncommittedPos + "-" + id); }
@Override public boolean hasPendingTransaction() { return undoLog.size() > 0; }