use of herddb.utils.Bytes 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.utils.Bytes in project herddb by diennea.
the class TableManager method createImmutablePage.
/**
* Create a new page with given data, save it and update keyToPage records
* <p>
* Will not place any lock, this method should be invoked at startup time or during checkpoint: <b>during
* "stop-the-world" procedures!</b>
* </p>
*/
private long createImmutablePage(Map<Bytes, Record> newPage, long newPageSize) throws DataStorageManagerException {
final Long pageId = nextPageId++;
final DataPage dataPage = buildImmutableDataPage(pageId, newPage, newPageSize);
LOGGER.log(Level.FINER, "createNewPage table {0}, pageId={1} with {2} records, {3} logical page size", new Object[] { table.name, pageId, newPage.size(), newPageSize });
dataStorageManager.writePage(tableSpaceUUID, table.uuid, pageId, newPage.values());
pageSet.pageCreated(pageId, dataPage);
pages.put(pageId, dataPage);
/* We mustn't update currentDirtyRecordsPage. This page isn't created to host live dirty data */
final Page.Metadata unload = pageReplacementPolicy.add(dataPage);
if (unload != null) {
unload.owner.unload(unload.pageId);
}
for (Bytes key : newPage.keySet()) {
keyToPage.put(key, pageId);
}
return pageId;
}
use of herddb.utils.Bytes in project herddb by diennea.
the class TableManager method executeGet.
private StatementExecutionResult executeGet(GetStatement get, Transaction transaction, StatementEvaluationContext context) throws StatementExecutionException, DataStorageManagerException {
Bytes key = new Bytes(get.getKey().computeNewValue(null, context, tableContext));
Predicate predicate = get.getPredicate();
boolean requireLock = get.isRequireLock();
long transactionId = transaction != null ? transaction.transactionId : 0;
LockHandle lock = (transaction != null || requireLock) ? lockForRead(key, transaction) : null;
try {
if (transaction != null) {
if (transaction.recordDeleted(table.name, key)) {
return GetResult.NOT_FOUND(transactionId);
}
Record loadedInTransaction = transaction.recordUpdated(table.name, key);
if (loadedInTransaction != null) {
if (predicate != null && !predicate.evaluate(loadedInTransaction, context)) {
return GetResult.NOT_FOUND(transactionId);
}
return new GetResult(transactionId, loadedInTransaction, table);
}
loadedInTransaction = transaction.recordInserted(table.name, key);
if (loadedInTransaction != null) {
if (predicate != null && !predicate.evaluate(loadedInTransaction, context)) {
return GetResult.NOT_FOUND(transactionId);
}
return new GetResult(transactionId, loadedInTransaction, table);
}
}
Long pageId = keyToPage.get(key);
if (pageId == null) {
return GetResult.NOT_FOUND(transactionId);
}
Record loaded = fetchRecord(key, pageId, null);
if (loaded == null || (predicate != null && !predicate.evaluate(loaded, context))) {
return GetResult.NOT_FOUND(transactionId);
}
return new GetResult(transactionId, loaded, table);
} finally {
if (transaction == null && lock != null) {
locksManager.releaseReadLockForKey(key, lock);
}
}
}
use of herddb.utils.Bytes 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.utils.Bytes in project herddb by diennea.
the class TableManager method applyDelete.
private void applyDelete(Bytes key) throws DataStorageManagerException {
/* This could be a normal or a temporary modifiable page */
final Long pageId = keyToPage.remove(key);
if (pageId == null) {
throw new IllegalStateException("corrupted transaction log: key " + key + " is not present in table " + table.tablespace + "." + table.name);
}
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Deleted key " + key + " from page " + pageId + " from table " + table.tablespace + "." + table.name);
}
/*
* We'll try to remove the record if in a writable page, otherwise we'll simply set the old page
* as dirty.
*/
final Map<String, AbstractIndexManager> indexes = tableSpaceManager.getIndexesOnTable(table.name);
/*
* When index is enabled we need the old value to update them, we'll force the page load only if that
* record is really needed.
*/
final DataPage page;
final Record previous;
if (indexes == null) {
/* We don't need the page if isn't loaded or isn't a mutable new page */
page = newPages.get(pageId);
if (page != null) {
pageReplacementPolicy.pageHit(page);
previous = page.get(key);
if (previous == null) {
throw new IllegalStateException("corrupted PK: old page " + pageId + " for deleted record at " + key + " was not found in table " + table.tablespace + "." + table.name);
}
} else {
previous = null;
}
} else {
/* We really need the page for update index old values */
page = loadPageToMemory(pageId, false);
previous = page.get(key);
if (previous == null) {
throw new IllegalStateException("corrupted PK: old page " + pageId + " for deleted record at " + key + " was not found in table " + table.tablespace + "." + table.name);
}
}
if (page == null || page.immutable) {
/* Unloaded or immutable, set it as dirty */
pageSet.setPageDirty(pageId, previous);
} else {
/* Mutable page, need to check if still modifiable or already unloaded */
final Lock lock = page.pageLock.readLock();
lock.lock();
try {
if (page.writable) {
/* We can modify the page directly */
page.remove(key);
} else {
/* Unfortunately is not writable (anymore), set it as dirty */
pageSet.setPageDirty(pageId, previous);
}
} finally {
lock.unlock();
}
}
if (indexes != null) {
/* If there are indexes e have already forced a page load and previous record has been loaded */
DataAccessor values = previous.getDataAccessor(table);
for (AbstractIndexManager index : indexes.values()) {
Bytes indexKey = RecordSerializer.serializeIndexKey(values, index.getIndex(), index.getColumnNames());
index.recordDeleted(key, indexKey);
}
}
}
Aggregations