use of herddb.model.StatementExecutionException in project herddb by diennea.
the class TableManager method executeInsert.
private StatementExecutionResult executeInsert(InsertStatement insert, Transaction transaction, StatementEvaluationContext context) throws StatementExecutionException, DataStorageManagerException {
/*
an insert can succeed only if the row is valid and the "keys" structure does not contain the requested key
the insert will add the row in the 'buffer' without assigning a page to it
locks: the insert uses global 'insert' lock on the table
the insert will update the 'maxKey' for auto_increment primary keys
*/
Bytes key = new Bytes(insert.getKeyFunction().computeNewValue(null, context, tableContext));
byte[] value = insert.getValuesFunction().computeNewValue(new Record(key, null), context, tableContext);
final long size = DataPage.estimateEntrySize(key, value);
if (size > maxLogicalPageSize) {
throw new RecordTooBigException("New record " + key + " is to big to be inserted: size " + size + ", max size " + maxLogicalPageSize);
}
LockHandle lock = lockForWrite(key, transaction);
try {
if (transaction != null) {
if (transaction.recordDeleted(table.name, key)) {
// OK, INSERT on a DELETED record inside this transaction
} else if (transaction.recordInserted(table.name, key) != null) {
// ERROR, INSERT on a INSERTED record inside this transaction
throw new DuplicatePrimaryKeyException(key, "key " + key + ", decoded as " + RecordSerializer.deserializePrimaryKey(key.data, table) + ", already exists in table " + table.name + " inside transaction " + transaction.transactionId);
} else if (keyToPage.containsKey(key)) {
throw new DuplicatePrimaryKeyException(key, "key " + key + ", decoded as " + RecordSerializer.deserializePrimaryKey(key.data, table) + ", already exists in table " + table.name + " during transaction " + transaction.transactionId);
}
} else if (keyToPage.containsKey(key)) {
throw new DuplicatePrimaryKeyException(key, "key " + key + ", decoded as " + RecordSerializer.deserializePrimaryKey(key.data, table) + ", already exists in table " + table.name);
}
LogEntry entry = LogEntryFactory.insert(table, key.data, value, transaction);
CommitLogResult pos = log.log(entry, entry.transactionId <= 0);
apply(pos, entry, false);
return new DMLStatementExecutionResult(entry.transactionId, 1, key, insert.isReturnValues() ? Bytes.from_array(value) : null);
} catch (LogNotAvailableException err) {
throw new StatementExecutionException(err);
} finally {
if (transaction == null) {
locksManager.releaseWriteLockForKey(key, lock);
}
}
}
use of herddb.model.StatementExecutionException in project herddb by diennea.
the class SystablespacereplicastateTableManager method buildVirtualRecordList.
@Override
protected Iterable<Record> buildVirtualRecordList() throws StatementExecutionException {
try {
Collection<String> names = tableSpaceManager.getMetadataStorageManager().listTableSpaces();
long now = System.currentTimeMillis();
List<Record> result = new ArrayList<>();
for (String name : names) {
TableSpace t = tableSpaceManager.getMetadataStorageManager().describeTableSpace(name);
if (t != null) {
List<TableSpaceReplicaState> tableSpaceReplicaStates = tableSpaceManager.getMetadataStorageManager().getTableSpaceReplicaState(t.uuid);
for (TableSpaceReplicaState state : tableSpaceReplicaStates) {
result.add(RecordSerializer.makeRecord(table, "tablespace_name", t.name, "uuid", t.uuid, "nodeid", state.nodeId, "timestamp", new java.sql.Timestamp(state.timestamp), "maxleaderinactivitytime", t.maxLeaderInactivityTime, "inactivitytime", now - state.timestamp, "mode", TableSpaceReplicaState.modeToSQLString(state.mode)));
}
}
}
return result;
} catch (MetadataStorageManagerException error) {
throw new StatementExecutionException(error);
}
}
use of herddb.model.StatementExecutionException in project herddb by diennea.
the class SystablespacesTableManager method buildVirtualRecordList.
@Override
protected Iterable<Record> buildVirtualRecordList() throws StatementExecutionException {
try {
Collection<String> names = tableSpaceManager.getMetadataStorageManager().listTableSpaces();
List<Record> result = new ArrayList<>();
for (String name : names) {
TableSpace t = tableSpaceManager.getMetadataStorageManager().describeTableSpace(name);
if (t != null) {
result.add(RecordSerializer.makeRecord(table, "tablespace_name", t.name, "uuid", t.uuid, "leader", t.leaderId, "expectedreplicacount", t.expectedReplicaCount, "maxleaderinactivitytime", t.maxLeaderInactivityTime, "replica", t.replicas.stream().collect(Collectors.joining(","))));
}
}
return result;
} catch (MetadataStorageManagerException error) {
throw new StatementExecutionException(error);
}
}
use of herddb.model.StatementExecutionException in project herddb by diennea.
the class TableManager method executeGetAsync.
private CompletableFuture<StatementExecutionResult> executeGetAsync(GetStatement get, Transaction transaction, StatementEvaluationContext context) {
Bytes key;
try {
key = Bytes.from_nullable_array(get.getKey().computeNewValue(null, context, tableContext));
} catch (StatementExecutionException validationError) {
return Futures.exception(validationError);
}
Predicate predicate = get.getPredicate();
boolean requireLock = get.isRequireLock();
boolean useWriteLock = requireLock && context.isForceAcquireWriteLock();
long transactionId = transaction != null ? transaction.transactionId : 0;
LockHandle lock = (transaction != null || requireLock) ? (useWriteLock ? lockForWrite(key, transaction) : lockForRead(key, transaction)) : null;
CompletableFuture<StatementExecutionResult> res = null;
try {
if (transaction != null) {
if (transaction.recordDeleted(table.name, key)) {
res = CompletableFuture.completedFuture(GetResult.NOT_FOUND(transactionId));
} else {
Record loadedInTransaction = transaction.recordUpdated(table.name, key);
if (loadedInTransaction != null) {
if (predicate != null && !predicate.evaluate(loadedInTransaction, context)) {
res = CompletableFuture.completedFuture(GetResult.NOT_FOUND(transactionId));
} else {
res = CompletableFuture.completedFuture(new GetResult(transactionId, loadedInTransaction, table));
}
} else {
loadedInTransaction = transaction.recordInserted(table.name, key);
if (loadedInTransaction != null) {
if (predicate != null && !predicate.evaluate(loadedInTransaction, context)) {
res = CompletableFuture.completedFuture(GetResult.NOT_FOUND(transactionId));
} else {
res = CompletableFuture.completedFuture(new GetResult(transactionId, loadedInTransaction, table));
}
}
}
}
}
if (res == null) {
Long pageId = keyToPage.get(key);
if (pageId == null) {
res = CompletableFuture.completedFuture(GetResult.NOT_FOUND(transactionId));
} else {
Record loaded = fetchRecord(key, pageId, null);
if (loaded == null || (predicate != null && !predicate.evaluate(loaded, context))) {
res = CompletableFuture.completedFuture(GetResult.NOT_FOUND(transactionId));
} else {
res = CompletableFuture.completedFuture(new GetResult(transactionId, loaded, table));
}
}
}
if (lock != null) {
if (transaction == null) {
res.whenComplete((r, e) -> {
locksManager.releaseReadLock(lock);
});
} else if (!context.isForceRetainReadLock() && !lock.write) {
transaction.releaseLockOnKey(table.name, key, locksManager);
}
}
return res;
} catch (HerdDBInternalException err) {
return Futures.exception(err);
}
}
use of herddb.model.StatementExecutionException in project herddb by diennea.
the class TableManager method executeInsertAsync.
private CompletableFuture<StatementExecutionResult> executeInsertAsync(InsertStatement insert, Transaction transaction, StatementEvaluationContext context) {
/*
an insert can succeed only if the row is valid and the "keys" structure does not contain the requested key
the insert will add the row in the 'buffer' without assigning a page to it
locks: the insert uses global 'insert' lock on the table
the insert will update the 'maxKey' for auto_increment primary keys
*/
Bytes key;
byte[] value;
try {
key = Bytes.from_array(insert.getKeyFunction().computeNewValue(null, context, tableContext));
value = insert.getValuesFunction().computeNewValue(new Record(key, null), context, tableContext);
} catch (StatementExecutionException validationError) {
return Futures.exception(validationError);
} catch (Throwable validationError) {
return Futures.exception(new StatementExecutionException(validationError));
}
List<UniqueIndexLockReference> uniqueIndexes = null;
Map<String, AbstractIndexManager> indexes = tableSpaceManager.getIndexesOnTable(table.name);
if (indexes != null || table.foreignKeys != null) {
try {
DataAccessor values = new Record(key, Bytes.from_array(value)).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);
}
uniqueIndexes.add(new UniqueIndexLockReference(index, indexKey));
} else {
RecordSerializer.validateIndexableValue(values, index.getIndex(), index.getColumnNames());
}
}
}
} catch (IllegalArgumentException | herddb.utils.IllegalDataAccessException | StatementExecutionException err) {
if (err instanceof StatementExecutionException) {
return Futures.exception(err);
} else {
return Futures.exception(new StatementExecutionException(err.getMessage(), err));
}
}
}
final long size = DataPage.estimateEntrySize(key, value);
if (size > maxLogicalPageSize) {
return Futures.exception(new RecordTooBigException("New record " + key + " is to big to be inserted: size " + size + ", max size " + maxLogicalPageSize));
}
CompletableFuture<StatementExecutionResult> res = null;
LockHandle lock = null;
try {
lock = lockForWrite(key, transaction);
if (uniqueIndexes != null) {
for (UniqueIndexLockReference uniqueIndexLock : uniqueIndexes) {
AbstractIndexManager index = uniqueIndexLock.indexManager;
LockHandle lockForIndex = lockForWrite(uniqueIndexLock.key, transaction, index.getIndexName(), index.getLockManager());
if (transaction == null) {
uniqueIndexLock.lockHandle = lockForIndex;
}
if (index.valueAlreadyMapped(uniqueIndexLock.key, null)) {
res = Futures.exception(new UniqueIndexContraintViolationException(index.getIndexName(), key, "key " + key + ", already exists in table " + table.name + " on UNIQUE index " + index.getIndexName()));
}
if (res != null) {
break;
}
}
}
} catch (HerdDBInternalException err) {
res = Futures.exception(err);
}
boolean fallbackToUpsert = false;
if (res == null) {
if (transaction != null) {
if (transaction.recordDeleted(table.name, key)) {
// OK, INSERT on a DELETED record inside this transaction
} else if (transaction.recordInserted(table.name, key) != null) {
// ERROR, INSERT on a INSERTED record inside this transaction
res = Futures.exception(new DuplicatePrimaryKeyException(key, "key " + key + ", decoded as " + RecordSerializer.deserializePrimaryKey(key, table) + ", already exists in table " + table.name + " inside transaction " + transaction.transactionId));
} else if (keyToPage.containsKey(key)) {
if (insert.isUpsert()) {
fallbackToUpsert = true;
} else {
res = Futures.exception(new DuplicatePrimaryKeyException(key, "key " + key + ", decoded as " + RecordSerializer.deserializePrimaryKey(key, table) + ", already exists in table " + table.name + " during transaction " + transaction.transactionId));
}
}
} else if (keyToPage.containsKey(key)) {
if (insert.isUpsert()) {
fallbackToUpsert = true;
} else {
res = Futures.exception(new DuplicatePrimaryKeyException(key, "key " + key + ", decoded as " + RecordSerializer.deserializePrimaryKey(key, table) + ", already exists in table " + table.name));
}
}
}
if (res == null) {
LogEntry entry;
if (fallbackToUpsert) {
entry = LogEntryFactory.update(table, key, Bytes.from_array(value), transaction);
} else {
entry = LogEntryFactory.insert(table, key, Bytes.from_array(value), transaction);
}
CommitLogResult pos = log.log(entry, entry.transactionId <= 0);
res = pos.logSequenceNumber.thenApplyAsync((lsn) -> {
apply(pos, entry, false);
return new DMLStatementExecutionResult(entry.transactionId, 1, key, insert.isReturnValues() ? Bytes.from_array(value) : null);
}, tableSpaceManager.getCallbacksExecutor());
}
if (uniqueIndexes != null) {
// TODO: reverse order
for (UniqueIndexLockReference uniqueIndexLock : uniqueIndexes) {
res = releaseWriteLock(res, uniqueIndexLock.lockHandle, uniqueIndexLock.indexManager.getLockManager());
}
}
if (transaction == null) {
res = releaseWriteLock(res, lock);
}
return res;
}
Aggregations