use of herddb.model.Transaction in project herddb by diennea.
the class TableSpaceManager method alterTable.
private StatementExecutionResult alterTable(AlterTableStatement statement, TransactionContext transactionContext, StatementEvaluationContext context) throws StatementExecutionException {
boolean lockAcquired = false;
if (context.getTableSpaceLock() == 0) {
long lockStamp = acquireWriteLock(statement);
context.setTableSpaceLock(lockStamp);
lockAcquired = true;
}
try {
if (transactionContext.transactionId > 0) {
Transaction transaction = transactions.get(transactionContext.transactionId);
if (transactionContext.transactionId > 0 && transaction == null) {
throw new StatementExecutionException("transaction " + transactionContext.transactionId + " does not exist on tablespace " + tableSpaceName);
}
if (transaction != null && !transaction.tableSpace.equals(tableSpaceName)) {
throw new StatementExecutionException("transaction " + transaction.transactionId + " is for tablespace " + transaction.tableSpace + ", not for " + tableSpaceName);
}
LOGGER.log(Level.INFO, "Implicitly committing transaction " + transactionContext.transactionId + " due to an ALTER TABLE statement in tablespace " + tableSpaceName);
try {
commitTransaction(new CommitTransactionStatement(tableSpaceName, transactionContext.transactionId), context).join();
} catch (CompletionException err) {
throw new StatementExecutionException(err);
}
transactionContext = TransactionContext.NO_TRANSACTION;
}
AbstractTableManager tableManager = tables.get(statement.getTable());
if (tableManager == null) {
throw new TableDoesNotExistException("no table " + statement.getTable() + " in tablespace " + tableSpaceName + "," + " only " + tables.keySet());
}
Table oldTable = tableManager.getTable();
Table[] childrenTables = collectChildrenTables(oldTable);
if (childrenTables != null) {
for (Table child : childrenTables) {
for (String col : statement.getDropColumns()) {
for (ForeignKeyDef fk : child.foreignKeys) {
if (fk.parentTableId.equals(oldTable.uuid)) {
if (Stream.of(fk.parentTableColumns).anyMatch(c -> c.equalsIgnoreCase(col))) {
throw new StatementExecutionException("Cannot drop column " + oldTable.name + "." + col + " because of foreign key constraint " + fk.name + " on table " + child.name);
}
}
}
}
}
}
Table newTable;
try {
newTable = tableManager.getTable().applyAlterTable(statement);
} catch (IllegalArgumentException error) {
throw new StatementExecutionException(error);
}
validateAlterTable(newTable, context);
LogEntry entry = LogEntryFactory.alterTable(newTable, null);
try {
CommitLogResult pos = log.log(entry, entry.transactionId <= 0);
apply(pos, entry, false);
} catch (Exception err) {
throw new StatementExecutionException(err);
}
// Here transactionId is always 0, because transaction is implicitly committed
return new DDLStatementExecutionResult(transactionContext.transactionId);
} finally {
if (lockAcquired) {
releaseWriteLock(context.getTableSpaceLock(), statement);
context.setTableSpaceLock(0);
}
}
}
use of herddb.model.Transaction in project herddb by diennea.
the class TableSpaceManager method processAbandonedTransactions.
void processAbandonedTransactions() {
if (!leader) {
return;
}
long now = System.currentTimeMillis();
long timeout = dbmanager.getAbandonedTransactionsTimeout();
if (timeout <= 0) {
return;
}
long abandonedTransactionTimeout = now - timeout;
for (Transaction t : transactions.values()) {
if (t.isAbandoned(abandonedTransactionTimeout)) {
LOGGER.log(Level.SEVERE, "forcing rollback of abandoned transaction {0}," + " created locally at {1}," + " last activity locally at {2}", new Object[] { t.transactionId, new java.sql.Timestamp(t.localCreationTimestamp), new java.sql.Timestamp(t.lastActivityTs) });
try {
if (!validateTransactionBeforeTxCommand(t.transactionId, false)) {
// Continue to check next transaction
continue;
}
} catch (StatementExecutionException e) {
LOGGER.log(Level.SEVERE, "Failed to validate transaction {0}: {1}", new Object[] { t.transactionId, e.getMessage() });
// Continue to check next transaction
continue;
} catch (RuntimeException e) {
LOGGER.log(Level.SEVERE, "Failed to validate transaction {0}", new Object[] { t.transactionId, e });
// Continue to check next transaction
continue;
}
long lockStamp = acquireReadLock("forceRollback" + t.transactionId);
try {
forceTransactionRollback(t.transactionId);
} finally {
releaseReadLock(lockStamp, "forceRollback" + t.transactionId);
}
}
}
}
use of herddb.model.Transaction in project herddb by diennea.
the class BookKeeperDataStorageManager method writeTransactionsAtCheckpoint.
@Override
public Collection<PostCheckpointAction> writeTransactionsAtCheckpoint(String tableSpace, LogSequenceNumber sequenceNumber, Collection<Transaction> transactions) throws DataStorageManagerException {
if (sequenceNumber.isStartOfTime() && !transactions.isEmpty()) {
throw new DataStorageManagerException("impossible to write a non empty transactions list at start-of-time");
}
String checkPointFile = getTablespaceTransactionsFile(tableSpace, sequenceNumber);
LOGGER.log(Level.FINE, "writeTransactionsAtCheckpoint for tableSpace {0} sequenceNumber {1} to {2}, active transactions {3}", new Object[] { tableSpace, sequenceNumber, checkPointFile, transactions.size() });
try (VisibleByteArrayOutputStream buffer = new VisibleByteArrayOutputStream();
ExtendedDataOutputStream dout = new ExtendedDataOutputStream(buffer)) {
// version
dout.writeVLong(1);
// flags for future implementations
dout.writeVLong(0);
dout.writeUTF(tableSpace);
dout.writeZLong(sequenceNumber.ledgerId);
dout.writeZLong(sequenceNumber.offset);
dout.writeInt(transactions.size());
for (Transaction t : transactions) {
t.serialize(dout);
}
dout.flush();
writeZNodeEnforceOwnership(tableSpace, checkPointFile, buffer.toByteArray(), null);
} catch (IOException err) {
throw new DataStorageManagerException(err);
}
Collection<PostCheckpointAction> result = new ArrayList<>();
String tableSpaceDirectory = getTableSpaceZNode(tableSpace);
List<String> stream = zkGetChildren(tableSpaceDirectory);
for (String p : stream) {
if (isTransactionsFile(p)) {
try {
byte[] content = readZNode(checkPointFile, new Stat());
if (content != null) {
LogSequenceNumber logPositionInFile = readLogSequenceNumberFromTransactionsFile(tableSpace, content, p);
if (sequenceNumber.after(logPositionInFile)) {
LOGGER.log(Level.FINEST, "transactions metadata file " + p + ". will be deleted after checkpoint end");
result.add(new DeleteZNodeAction(tableSpace, "transactions", "delete transactions file " + p, p));
}
}
} catch (DataStorageManagerException ignore) {
LOGGER.log(Level.SEVERE, "Unparsable transactions file " + p, ignore);
result.add(new DeleteZNodeAction(tableSpace, "transactions", "delete unparsable transactions file " + p, p));
}
}
}
return result;
}
use of herddb.model.Transaction in project herddb by diennea.
the class BookKeeperDataStorageManager method loadTransactions.
@Override
public void loadTransactions(LogSequenceNumber sequenceNumber, String tableSpace, Consumer<Transaction> consumer) throws DataStorageManagerException {
try {
String file = getTablespaceTransactionsFile(tableSpace, sequenceNumber);
byte[] content = readZNode(file, new Stat());
boolean exists = content != null;
LOGGER.log(Level.INFO, "loadTransactions " + sequenceNumber + " for tableSpace " + tableSpace + " from file " + file + " (exists: " + exists + ")");
if (!exists) {
return;
}
try (InputStream input = new ByteArrayInputStream(content);
ExtendedDataInputStream din = new ExtendedDataInputStream(input)) {
// version
long version = din.readVLong();
// flags for future implementations
long flags = din.readVLong();
if (version != 1 || flags != 0) {
throw new DataStorageManagerException("corrupted transaction list file " + file);
}
String readname = din.readUTF();
if (!readname.equals(tableSpace)) {
throw new DataStorageManagerException("file " + file + " is not for spablespace " + tableSpace);
}
long ledgerId = din.readZLong();
long offset = din.readZLong();
if (ledgerId != sequenceNumber.ledgerId || offset != sequenceNumber.offset) {
throw new DataStorageManagerException("file " + file + " is not for sequence number " + sequenceNumber);
}
int numTransactions = din.readInt();
for (int i = 0; i < numTransactions; i++) {
Transaction tx = Transaction.deserialize(tableSpace, din);
consumer.accept(tx);
}
}
} catch (IOException err) {
throw new DataStorageManagerException(err);
}
}
use of herddb.model.Transaction in project herddb by diennea.
the class SimpleScanTest method testCloseResultSetsOnCloseConnection.
@Test
public void testCloseResultSetsOnCloseConnection() throws Exception {
try (Server server = new Server(herddb.jdbc.TestUtils.newServerConfigurationWithAutoPort(folder.newFolder().toPath()))) {
server.start();
server.waitForStandaloneBoot();
try (HDBClient client = new HDBClient(new ClientConfiguration(folder.newFolder().toPath()))) {
client.setClientSideMetadataProvider(new StaticClientSideMetadataProvider(server));
try (BasicHerdDBDataSource dataSource = new BasicHerdDBDataSource(client)) {
try (Connection con = dataSource.getConnection();
Statement statement = con.createStatement()) {
statement.execute("CREATE TABLE mytable (k1 string primary key, n1 int, l1 long, t1 timestamp, nu string, b1 bool, d1 double)");
}
try (Connection con = dataSource.getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO mytable(k1,n1,l1,t1,nu,b1,d1) values(?,?,?,?,?,?,?)")) {
for (int n = 0; n < 10; ++n) {
int i = 1;
statement.setString(i++, "mykey_" + n);
statement.setInt(i++, n);
statement.setLong(i++, n);
statement.setTimestamp(i++, new java.sql.Timestamp(System.currentTimeMillis()));
statement.setString(i++, null);
statement.setBoolean(i++, true);
statement.setDouble(i++, n + 0.5);
statement.addBatch();
}
int[] batches = statement.executeBatch();
Assert.assertEquals(10, batches.length);
for (int batch : batches) {
Assert.assertEquals(1, batch);
}
}
try (Connection con = dataSource.getConnection()) {
con.setAutoCommit(false);
Transaction tx;
try (Statement s = con.createStatement()) {
// force the creation of the transaction, by issuing a DML command
s.executeUpdate("UPDATE mytable set n1=1 where k1 ='aaa'");
}
try (PreparedStatement statement = con.prepareStatement("SELECT n1, k1 FROM mytable")) {
statement.setFetchSize(1);
ResultSet rs = statement.executeQuery();
assertTrue(rs.next());
List<Transaction> transactions = server.getManager().getTableSpaceManager(TableSpace.DEFAULT).getTransactions();
assertEquals(1, transactions.size());
tx = transactions.get(0);
assertEquals(1, tx.getRefCount());
}
// close statement -> close result set -> transaction refcount = 0
// closing of scanners is non blocking, we have to wait
TestUtils.waitForCondition(() -> tx.getRefCount() == 0, NOOP, 100);
}
Transaction tx;
try (Connection con = dataSource.getConnection()) {
con.setAutoCommit(false);
try (Statement s = con.createStatement()) {
// force the creation of the transaction, by issuing a DML command
s.executeUpdate("UPDATE mytable set n1=1 where k1 ='aaa'");
}
PreparedStatement statement = con.prepareStatement("SELECT n1, k1 FROM mytable");
statement.setFetchSize(1);
ResultSet rs = statement.executeQuery();
assertTrue(rs.next());
List<Transaction> transactions = server.getManager().getTableSpaceManager(TableSpace.DEFAULT).getTransactions();
assertEquals(1, transactions.size());
tx = transactions.get(0);
assertEquals(1, tx.getRefCount());
}
// close connection -> close statement -> close result set -> transaction refcount = 0 (and rolled back)
TestUtils.waitForCondition(() -> tx.getRefCount() == 0, NOOP, 100);
}
}
}
}
Aggregations