use of herddb.model.StatementExecutionException in project herddb by diennea.
the class TableManager method executeUpdateAsync.
private CompletableFuture<StatementExecutionResult> executeUpdateAsync(UpdateStatement update, Transaction transaction, StatementEvaluationContext context) throws StatementExecutionException, DataStorageManagerException {
// LOGGER.log(Level.SEVERE, "executeUpdateAsync, " + update + ", transaction " + transaction);
AtomicInteger updateCount = new AtomicInteger();
Holder<Bytes> lastKey = new Holder<>();
Holder<byte[]> lastValue = new Holder<>();
/*
an update can succeed only if the row is valid, the key is contains in the "keys" structure
the update will simply override the value of the row, assigning a null page to the row
the update can have a 'where' predicate which is to be evaluated against the decoded row, the update will be executed only if the predicate returns boolean 'true' value (CAS operation)
locks: the update uses a lock on the the key
*/
RecordFunction function = update.getFunction();
long transactionId = transaction != null ? transaction.transactionId : 0;
Predicate predicate = update.getPredicate();
Map<String, AbstractIndexManager> indexes = tableSpaceManager.getIndexesOnTable(table.name);
ScanStatement scan = new ScanStatement(table.tablespace, table, predicate);
List<CompletableFuture<PendingLogEntryWork>> writes = new ArrayList<>();
try {
accessTableData(scan, context, new ScanResultOperation() {
@Override
public void accept(Record current, LockHandle lockHandle) throws StatementExecutionException, LogNotAvailableException, DataStorageManagerException {
List<UniqueIndexLockReference> uniqueIndexes = null;
byte[] newValue;
try {
if (childrenTables != null) {
DataAccessor currentValues = current.getDataAccessor(table);
for (Table childTable : childrenTables) {
executeForeignKeyConstraintsAsParentTable(childTable, currentValues, context, transaction, false);
}
}
newValue = function.computeNewValue(current, context, tableContext);
if (indexes != null || table.foreignKeys != null) {
DataAccessor values = new Record(current.key, Bytes.from_array(newValue)).getDataAccessor(table);
if (table.foreignKeys != null) {
for (ForeignKeyDef fk : table.foreignKeys) {
checkForeignKeyConstraintsAsChildTable(fk, values, context, transaction);
}
}
if (indexes != null) {
for (AbstractIndexManager index : indexes.values()) {
if (index.isUnique()) {
Bytes indexKey = RecordSerializer.serializeIndexKey(values, index.getIndex(), index.getColumnNames());
if (uniqueIndexes == null) {
uniqueIndexes = new ArrayList<>(1);
}
UniqueIndexLockReference uniqueIndexLock = new UniqueIndexLockReference(index, indexKey);
uniqueIndexes.add(uniqueIndexLock);
LockHandle lockForIndex = lockForWrite(uniqueIndexLock.key, transaction, index.getIndexName(), index.getLockManager());
if (transaction == null) {
uniqueIndexLock.lockHandle = lockForIndex;
}
if (index.valueAlreadyMapped(indexKey, current.key)) {
throw new UniqueIndexContraintViolationException(index.getIndexName(), indexKey, "Value " + indexKey + " already present in index " + index.getIndexName());
}
} else {
RecordSerializer.validateIndexableValue(values, index.getIndex(), index.getColumnNames());
}
}
}
}
} catch (IllegalArgumentException | herddb.utils.IllegalDataAccessException | StatementExecutionException err) {
locksManager.releaseLock(lockHandle);
StatementExecutionException finalError;
if (!(err instanceof StatementExecutionException)) {
finalError = new StatementExecutionException(err.getMessage(), err);
} else {
finalError = (StatementExecutionException) err;
}
CompletableFuture<PendingLogEntryWork> res = Futures.exception(finalError);
if (uniqueIndexes != null) {
for (UniqueIndexLockReference lock : uniqueIndexes) {
res = releaseWriteLock(res, lock.lockHandle, lock.indexManager.getLockManager());
}
}
writes.add(res);
return;
}
final long size = DataPage.estimateEntrySize(current.key, newValue);
if (size > maxLogicalPageSize) {
locksManager.releaseLock(lockHandle);
writes.add(Futures.exception(new RecordTooBigException("New version of record " + current.key + " is to big to be update: new size " + size + ", actual size " + DataPage.estimateEntrySize(current) + ", max size " + maxLogicalPageSize)));
return;
}
LogEntry entry = LogEntryFactory.update(table, current.key, Bytes.from_array(newValue), transaction);
CommitLogResult pos = log.log(entry, entry.transactionId <= 0);
final List<UniqueIndexLockReference> _uniqueIndexes = uniqueIndexes;
writes.add(pos.logSequenceNumber.thenApply(lsn -> new PendingLogEntryWork(entry, pos, lockHandle, _uniqueIndexes)));
lastKey.value = current.key;
lastValue.value = newValue;
updateCount.incrementAndGet();
}
}, transaction, true, true);
} catch (HerdDBInternalException err) {
LOGGER.log(Level.SEVERE, "bad error during an update", err);
return Futures.exception(err);
}
if (writes.isEmpty()) {
return CompletableFuture.completedFuture(new DMLStatementExecutionResult(transactionId, 0, null, null));
}
if (writes.size() == 1) {
return writes.get(0).whenCompleteAsync((pending, error) -> {
try {
// apply any of the DML operations
if (error == null) {
apply(pending.pos, pending.entry, false);
}
} finally {
releaseMultiplePendingLogEntryWorks(writes);
}
}, tableSpaceManager.getCallbacksExecutor()).thenApply((pending) -> {
return new DMLStatementExecutionResult(transactionId, updateCount.get(), lastKey.value, update.isReturnValues() ? (lastValue.value != null ? Bytes.from_array(lastValue.value) : null) : null);
});
} else {
return Futures.collect(writes).whenCompleteAsync((pendings, error) -> {
try {
// apply any of the DML operations
if (error == null) {
for (PendingLogEntryWork pending : pendings) {
apply(pending.pos, pending.entry, false);
}
}
} finally {
releaseMultiplePendingLogEntryWorks(writes);
}
}, tableSpaceManager.getCallbacksExecutor()).thenApply((pendings) -> {
return new DMLStatementExecutionResult(transactionId, updateCount.get(), lastKey.value, update.isReturnValues() ? (lastValue.value != null ? Bytes.from_array(lastValue.value) : null) : null);
});
}
}
use of herddb.model.StatementExecutionException in project herddb by diennea.
the class DBManager method createTableSpace.
private StatementExecutionResult createTableSpace(CreateTableSpaceStatement createTableSpaceStatement) throws StatementExecutionException {
TableSpace tableSpace;
try {
tableSpace = TableSpace.builder().leader(createTableSpaceStatement.getLeaderId()).name(createTableSpaceStatement.getTableSpace()).replicas(createTableSpaceStatement.getReplicas()).expectedReplicaCount(createTableSpaceStatement.getExpectedReplicaCount()).maxLeaderInactivityTime(createTableSpaceStatement.getMaxleaderinactivitytime()).build();
} catch (IllegalArgumentException invalid) {
throw new StatementExecutionException("invalid CREATE TABLESPACE statement: " + invalid.getMessage(), invalid);
}
try {
metadataStorageManager.registerTableSpace(tableSpace);
triggerActivator(ActivatorRunRequest.FULL);
if (createTableSpaceStatement.getWaitForTableSpaceTimeout() > 0) {
boolean okWait = false;
int poolTime = 100;
if (metadataStorageManager instanceof MemoryMetadataStorageManager || metadataStorageManager instanceof FileMetadataStorageManager) {
poolTime = 5;
}
LOGGER.log(Level.INFO, "waiting for " + tableSpace.name + ", uuid " + tableSpace.uuid + ", to be up withint " + createTableSpaceStatement.getWaitForTableSpaceTimeout() + " ms");
final int timeout = createTableSpaceStatement.getWaitForTableSpaceTimeout();
for (int i = 0; i < timeout; i += poolTime) {
List<TableSpaceReplicaState> replicateStates = metadataStorageManager.getTableSpaceReplicaState(tableSpace.uuid);
for (TableSpaceReplicaState ts : replicateStates) {
LOGGER.log(Level.INFO, "waiting for " + tableSpace.name + ", uuid " + tableSpace.uuid + ", to be up, replica state node: " + ts.nodeId + ", state: " + TableSpaceReplicaState.modeToSQLString(ts.mode) + ", ts " + new java.sql.Timestamp(ts.timestamp));
if (ts.mode == TableSpaceReplicaState.MODE_LEADER) {
okWait = true;
break;
}
}
if (okWait) {
break;
}
Thread.sleep(poolTime);
}
if (!okWait) {
throw new StatementExecutionException("tablespace " + tableSpace.name + ", uuid " + tableSpace.uuid + " has been created but leader " + tableSpace.leaderId + " did not start within " + createTableSpaceStatement.getWaitForTableSpaceTimeout() + " ms");
}
}
return new DDLStatementExecutionResult(TransactionContext.NOTRANSACTION_ID);
} catch (StatementExecutionException err) {
throw err;
} catch (Exception err) {
throw new StatementExecutionException(err);
}
}
use of herddb.model.StatementExecutionException in project herddb by diennea.
the class DBManager method dropTableSpace.
private StatementExecutionResult dropTableSpace(DropTableSpaceStatement dropTableSpaceStatement) throws StatementExecutionException {
try {
TableSpace previous = metadataStorageManager.describeTableSpace(dropTableSpaceStatement.getTableSpace());
if (previous == null) {
throw new TableSpaceDoesNotExistException(dropTableSpaceStatement.getTableSpace());
}
metadataStorageManager.dropTableSpace(dropTableSpaceStatement.getTableSpace(), previous);
triggerActivator(ActivatorRunRequest.TABLESPACEMANAGEMENT);
return new DDLStatementExecutionResult(TransactionContext.NOTRANSACTION_ID);
} catch (Exception err) {
throw new StatementExecutionException(err);
}
}
use of herddb.model.StatementExecutionException in project herddb by diennea.
the class TableSpaceManager method scan.
public DataScanner scan(ScanStatement statement, StatementEvaluationContext context, TransactionContext transactionContext, boolean lockRequired, boolean forWrite) throws StatementExecutionException {
boolean rollbackOnError = false;
if (transactionContext.transactionId == TransactionContext.AUTOTRANSACTION_ID && (lockRequired || forWrite || context.isForceAcquireWriteLock() || context.isForceRetainReadLock())) {
try {
// sync on beginTransaction
StatementExecutionResult newTransaction = Futures.result(beginTransactionAsync(context, true));
transactionContext = new TransactionContext(newTransaction.transactionId);
rollbackOnError = true;
} catch (Exception err) {
if (err.getCause() instanceof HerdDBInternalException) {
throw (HerdDBInternalException) err.getCause();
} else {
throw new StatementExecutionException(err.getCause());
}
}
}
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);
}
if (transaction != null) {
transaction.touch();
}
try {
String table = statement.getTable();
AbstractTableManager tableManager = tables.get(table);
if (tableManager == null) {
throw new TableDoesNotExistException("no table " + table + " in tablespace " + tableSpaceName);
}
if (tableManager.getCreatedInTransaction() > 0) {
if (transaction == null || transaction.transactionId != tableManager.getCreatedInTransaction()) {
throw new TableDoesNotExistException("no table " + table + " in tablespace " + tableSpaceName + ". created temporary in transaction " + tableManager.getCreatedInTransaction());
}
}
return tableManager.scan(statement, context, transaction, lockRequired, forWrite);
} catch (StatementExecutionException error) {
if (rollbackOnError) {
LOGGER.log(Level.FINE, tableSpaceName + " forcing rollback of implicit tx " + transactionContext.transactionId, error);
try {
rollbackTransaction(new RollbackTransactionStatement(tableSpaceName, transactionContext.transactionId), context).get();
} catch (ExecutionException err) {
throw new StatementExecutionException(err.getCause());
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
error.addSuppressed(ex);
}
}
throw error;
}
}
use of herddb.model.StatementExecutionException in project herddb by diennea.
the class TableSpaceManager method dropIndex.
private StatementExecutionResult dropIndex(DropIndexStatement statement, Transaction transaction, StatementEvaluationContext context) throws StatementExecutionException {
boolean lockAcquired = false;
if (context.getTableSpaceLock() == 0) {
long lockStamp = acquireWriteLock(statement);
context.setTableSpaceLock(lockStamp);
lockAcquired = true;
}
try {
if (!indexes.containsKey(statement.getIndexName())) {
if (statement.isIfExists()) {
return new DDLStatementExecutionResult(transaction != null ? transaction.transactionId : 0);
}
throw new IndexDoesNotExistException("index " + statement.getIndexName() + " does not exist " + statement.getIndexName() + " on tableSpace " + statement.getTableSpace());
}
if (transaction != null && transaction.isIndexDropped(statement.getIndexName())) {
if (statement.isIfExists()) {
return new DDLStatementExecutionResult(transaction.transactionId);
}
throw new IndexDoesNotExistException("index does not exist " + statement.getIndexName() + " on tableSpace " + statement.getTableSpace());
}
LogEntry entry = LogEntryFactory.dropIndex(statement.getIndexName(), transaction);
CommitLogResult pos;
try {
pos = log.log(entry, entry.transactionId <= 0);
} catch (LogNotAvailableException ex) {
throw new StatementExecutionException(ex);
}
apply(pos, entry, false);
return new DDLStatementExecutionResult(entry.transactionId);
} catch (DataStorageManagerException err) {
throw new StatementExecutionException(err);
} finally {
if (lockAcquired) {
releaseWriteLock(context.getTableSpaceLock(), statement);
context.setTableSpaceLock(0);
}
}
}
Aggregations