Search in sources :

Example 1 with BatchOrderedExecutor

use of herddb.utils.BatchOrderedExecutor 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)

Aggregations

IndexOperation (herddb.index.IndexOperation)1 PrimaryIndexSeek (herddb.index.PrimaryIndexSeek)1 LogEntry (herddb.log.LogEntry)1 Predicate (herddb.model.Predicate)1 Record (herddb.model.Record)1 StatementExecutionException (herddb.model.StatementExecutionException)1 DataStorageManagerException (herddb.storage.DataStorageManagerException)1 BatchOrderedExecutor (herddb.utils.BatchOrderedExecutor)1 Bytes (herddb.utils.Bytes)1 LockHandle (herddb.utils.LockHandle)1 Entry (java.util.Map.Entry)1 AtomicLong (java.util.concurrent.atomic.AtomicLong)1