Search in sources :

Example 1 with LockHandle

use of herddb.utils.LockHandle in project herddb by diennea.

the class TableManager method accessTableData.

private void accessTableData(ScanStatement statement, StatementEvaluationContext context, ScanResultOperation consumer, Transaction transaction, boolean lockRequired, boolean forWrite) throws StatementExecutionException {
    statement.validateContext(context);
    Predicate predicate = statement.getPredicate();
    long _start = System.currentTimeMillis();
    boolean acquireLock = transaction != null || forWrite || lockRequired;
    LocalScanPageCache lastPageRead = acquireLock ? null : new LocalScanPageCache();
    try {
        IndexOperation indexOperation = predicate != null ? predicate.getIndexOperation() : null;
        boolean primaryIndexSeek = indexOperation instanceof PrimaryIndexSeek;
        AbstractIndexManager useIndex = getIndexForTbleAccess(indexOperation);
        BatchOrderedExecutor.Executor<Map.Entry<Bytes, Long>> scanExecutor = (List<Map.Entry<Bytes, Long>> batch) -> {
            for (Map.Entry<Bytes, Long> entry : batch) {
                Bytes key = entry.getKey();
                boolean keep_lock = false;
                boolean already_locked = transaction != null && transaction.lookupLock(table.name, key) != null;
                LockHandle lock = acquireLock ? (forWrite ? lockForWrite(key, transaction) : lockForRead(key, transaction)) : null;
                try {
                    if (transaction != null) {
                        if (transaction.recordDeleted(table.name, key)) {
                            // skip this record. inside current transaction it has been deleted
                            continue;
                        }
                        Record record = transaction.recordUpdated(table.name, key);
                        if (record != null) {
                            // use current transaction version of the record
                            if (predicate == null || predicate.evaluate(record, context)) {
                                consumer.accept(record);
                                keep_lock = true;
                            }
                            continue;
                        }
                    }
                    Long pageId = entry.getValue();
                    if (pageId != null) {
                        boolean pkFilterCompleteMatch = false;
                        if (!primaryIndexSeek && predicate != null) {
                            Predicate.PrimaryKeyMatchOutcome outcome = predicate.matchesRawPrimaryKey(key, context);
                            if (outcome == Predicate.PrimaryKeyMatchOutcome.FAILED) {
                                continue;
                            } else if (outcome == Predicate.PrimaryKeyMatchOutcome.FULL_CONDITION_VERIFIED) {
                                pkFilterCompleteMatch = true;
                            }
                        }
                        Record record = fetchRecord(key, pageId, lastPageRead);
                        if (record != null && (pkFilterCompleteMatch || predicate == null || predicate.evaluate(record, context))) {
                            consumer.accept(record);
                            keep_lock = true;
                        }
                    }
                } finally {
                    // release the lock on the key if it did not match scan criteria
                    if (transaction == null) {
                        if (lock != null) {
                            if (forWrite) {
                                locksManager.releaseWriteLockForKey(key, lock);
                            } else {
                                locksManager.releaseReadLockForKey(key, lock);
                            }
                        }
                    } else if (!keep_lock && !already_locked) {
                        transaction.releaseLockOnKey(table.name, key, locksManager);
                    }
                }
            }
        };
        BatchOrderedExecutor<Map.Entry<Bytes, Long>> executor = new BatchOrderedExecutor<>(SORTED_PAGE_ACCESS_WINDOW_SIZE, scanExecutor, SORTED_PAGE_ACCESS_COMPARATOR);
        Stream<Map.Entry<Bytes, Long>> scanner = keyToPage.scanner(indexOperation, context, tableContext, useIndex);
        boolean exit = false;
        try {
            scanner.forEach(executor);
            executor.finish();
        } catch (ExitLoop exitLoop) {
            exit = !exitLoop.continueWithTransactionData;
            if (LOGGER.isLoggable(Level.FINEST)) {
                LOGGER.log(Level.FINEST, "exit loop during scan {0}, started at {1}: {2}", new Object[] { statement, new java.sql.Timestamp(_start), exitLoop.toString() });
            }
        } catch (final HerdDBInternalException error) {
            LOGGER.log(Level.SEVERE, "error during scan", error);
            if (error.getCause() instanceof StatementExecutionException) {
                throw (StatementExecutionException) error.getCause();
            } else if (error.getCause() instanceof DataStorageManagerException) {
                throw (DataStorageManagerException) error.getCause();
            } else if (error instanceof StatementExecutionException) {
                throw (StatementExecutionException) error;
            } else if (error instanceof DataStorageManagerException) {
                throw (DataStorageManagerException) error;
            } else {
                throw new StatementExecutionException(error);
            }
        }
        if (!exit && transaction != null) {
            consumer.beginNewRecordsInTransactionBlock();
            Collection<Record> newRecordsForTable = transaction.getNewRecordsForTable(table.name);
            for (Record record : newRecordsForTable) {
                if (!transaction.recordDeleted(table.name, record.key) && (predicate == null || predicate.evaluate(record, context))) {
                    consumer.accept(record);
                }
            }
        }
    } catch (ExitLoop exitLoop) {
        if (LOGGER.isLoggable(Level.FINEST)) {
            LOGGER.log(Level.FINEST, "exit loop during scan {0}, started at {1}: {2}", new Object[] { statement, new java.sql.Timestamp(_start), exitLoop.toString() });
        }
    } catch (StatementExecutionException err) {
        LOGGER.log(Level.SEVERE, "error during scan {0}, started at {1}: {2}", new Object[] { statement, new java.sql.Timestamp(_start), err.toString() });
        throw err;
    } catch (HerdDBInternalException err) {
        LOGGER.log(Level.SEVERE, "error during scan {0}, started at {1}: {2}", new Object[] { statement, new java.sql.Timestamp(_start), err.toString() });
        throw new StatementExecutionException(err);
    }
}
Also used : DataStorageManagerException(herddb.storage.DataStorageManagerException) StatementExecutionException(herddb.model.StatementExecutionException) Predicate(herddb.model.Predicate) PrimaryIndexSeek(herddb.index.PrimaryIndexSeek) Bytes(herddb.utils.Bytes) Entry(java.util.Map.Entry) LogEntry(herddb.log.LogEntry) Record(herddb.model.Record) LockHandle(herddb.utils.LockHandle) BatchOrderedExecutor(herddb.utils.BatchOrderedExecutor) IndexOperation(herddb.index.IndexOperation) AtomicLong(java.util.concurrent.atomic.AtomicLong)

Example 2 with LockHandle

use of herddb.utils.LockHandle 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);
        }
    }
}
Also used : Bytes(herddb.utils.Bytes) LockHandle(herddb.utils.LockHandle) DMLStatementExecutionResult(herddb.model.DMLStatementExecutionResult) DuplicatePrimaryKeyException(herddb.model.DuplicatePrimaryKeyException) Record(herddb.model.Record) CommitLogResult(herddb.log.CommitLogResult) RecordTooBigException(herddb.model.RecordTooBigException) LogEntry(herddb.log.LogEntry) StatementExecutionException(herddb.model.StatementExecutionException) LogNotAvailableException(herddb.log.LogNotAvailableException)

Example 3 with LockHandle

use of herddb.utils.LockHandle in project herddb by diennea.

the class TableManager method lockForRead.

private LockHandle lockForRead(Bytes key, Transaction transaction) {
    if (transaction != null) {
        LockHandle lock = transaction.lookupLock(table.name, key);
        if (lock != null) {
            // transaction already locked the key
            return lock;
        } else {
            lock = locksManager.acquireReadLockForKey(key);
            transaction.registerLockOnTable(this.table.name, lock);
            return lock;
        }
    } else {
        return locksManager.acquireReadLockForKey(key);
    }
}
Also used : LockHandle(herddb.utils.LockHandle)

Example 4 with LockHandle

use of herddb.utils.LockHandle in project herddb by diennea.

the class TableManager method scanForIndexRebuild.

@Override
public void scanForIndexRebuild(Consumer<Record> records) throws DataStorageManagerException {
    LocalScanPageCache localPageCache = new LocalScanPageCache();
    Consumer<Map.Entry<Bytes, Long>> scanExecutor = (Map.Entry<Bytes, Long> entry) -> {
        Bytes key = entry.getKey();
        LockHandle lock = lockForRead(key, null);
        try {
            Long pageId = entry.getValue();
            if (pageId != null) {
                Record record = fetchRecord(key, pageId, localPageCache);
                if (record != null) {
                    records.accept(record);
                }
            }
        } catch (DataStorageManagerException | StatementExecutionException error) {
            throw new RuntimeException(error);
        } finally {
            locksManager.releaseReadLockForKey(key, lock);
        }
    };
    try {
        Stream<Map.Entry<Bytes, Long>> scanner = keyToPage.scanner(null, StatementEvaluationContext.DEFAULT_EVALUATION_CONTEXT(), tableContext, null);
        scanner.forEach(scanExecutor);
    } catch (StatementExecutionException impossible) {
        throw new DataStorageManagerException(impossible);
    }
}
Also used : DataStorageManagerException(herddb.storage.DataStorageManagerException) LockHandle(herddb.utils.LockHandle) StatementExecutionException(herddb.model.StatementExecutionException) Bytes(herddb.utils.Bytes) Entry(java.util.Map.Entry) LogEntry(herddb.log.LogEntry) AtomicLong(java.util.concurrent.atomic.AtomicLong) Record(herddb.model.Record) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) ConcurrentMap(java.util.concurrent.ConcurrentMap)

Example 5 with LockHandle

use of herddb.utils.LockHandle 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);
        }
    }
}
Also used : Bytes(herddb.utils.Bytes) LockHandle(herddb.utils.LockHandle) GetResult(herddb.model.GetResult) AtomicLong(java.util.concurrent.atomic.AtomicLong) Record(herddb.model.Record) Predicate(herddb.model.Predicate)

Aggregations

LockHandle (herddb.utils.LockHandle)7 Record (herddb.model.Record)5 Bytes (herddb.utils.Bytes)5 AtomicLong (java.util.concurrent.atomic.AtomicLong)4 LogEntry (herddb.log.LogEntry)3 Predicate (herddb.model.Predicate)3 StatementExecutionException (herddb.model.StatementExecutionException)3 DataStorageManagerException (herddb.storage.DataStorageManagerException)2 Entry (java.util.Map.Entry)2 IndexOperation (herddb.index.IndexOperation)1 PrimaryIndexSeek (herddb.index.PrimaryIndexSeek)1 CommitLogResult (herddb.log.CommitLogResult)1 LogNotAvailableException (herddb.log.LogNotAvailableException)1 DMLStatementExecutionResult (herddb.model.DMLStatementExecutionResult)1 DuplicatePrimaryKeyException (herddb.model.DuplicatePrimaryKeyException)1 GetResult (herddb.model.GetResult)1 RecordTooBigException (herddb.model.RecordTooBigException)1 BatchOrderedExecutor (herddb.utils.BatchOrderedExecutor)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1