Search in sources :

Example 1 with Transaction

use of org.cojen.tupl.Transaction in project Tupl by cojen.

the class BasicRowUpdater method doDelete.

protected void doDelete(Trigger<R> trigger, R row) throws IOException {
    Cursor c = mCursor;
    Transaction txn = ViewUtils.enterScope(mTable.mSource, c.link());
    try {
        byte[] oldValue = c.value();
        if (oldValue != null) {
            // Don't pass the row in case the key columns were modified.
            trigger.delete(txn, c.key(), oldValue);
            c.commit(null);
        }
    } finally {
        txn.exit();
    }
}
Also used : Transaction(org.cojen.tupl.Transaction) Cursor(org.cojen.tupl.Cursor)

Example 2 with Transaction

use of org.cojen.tupl.Transaction in project Tupl by cojen.

the class BasicRowUpdater method doUpdateAsDeleteInsert.

/**
 * Called when the primary key changed.
 *
 * @param c positioned at key to delete; position isn't changed
 * @param key key to insert
 * @param value value to insert
 * @throws UniqueConstraintException
 */
private void doUpdateAsDeleteInsert(R row, Cursor c, byte[] key, byte[] value) throws IOException {
    Index source = mTable.mSource;
    Transaction txn = ViewUtils.enterScope(source, c.link());
    try {
        Trigger<R> trigger = mTable.getTrigger();
        if (trigger != null)
            while (true) {
                trigger.acquireShared();
                try {
                    int mode = trigger.mode();
                    if (mode == Trigger.SKIP) {
                        break;
                    }
                    if (mode != Trigger.DISABLED) {
                        byte[] oldValue = c.value();
                        if (oldValue != null) {
                            // Don't pass the row because the key columns were modified.
                            trigger.delete(txn, c.key(), oldValue);
                        }
                        trigger.insertP(txn, row, key, value);
                        break;
                    }
                } finally {
                    trigger.releaseShared();
                }
                trigger = mTable.trigger();
            }
        boolean result;
        RowPredicateLock<R> lock = mTable.mIndexLock;
        if (lock == null) {
            result = source.insert(txn, key, value);
        } else {
            lock.redoPredicateMode(txn);
            try (RowPredicateLock.Closer closer = lock.openAcquireP(txn, row, key, value)) {
                result = source.insert(txn, key, value);
            }
        }
        if (!result) {
            throw new UniqueConstraintException("Primary key");
        }
        c.commit(null);
    } finally {
        txn.exit();
    }
    postStoreKeyValue(txn);
}
Also used : UniqueConstraintException(org.cojen.tupl.UniqueConstraintException) Transaction(org.cojen.tupl.Transaction) Index(org.cojen.tupl.Index) RowPredicateLock(org.cojen.tupl.core.RowPredicateLock)

Example 3 with Transaction

use of org.cojen.tupl.Transaction in project Tupl by cojen.

the class AutoCommitRowUpdater method storeValue.

@Override
protected void storeValue(Trigger<R> trigger, R row, Cursor c, byte[] value) throws IOException {
    Transaction txn = c.link();
    byte[] oldValue = c.value();
    if (oldValue == null) {
        trigger.insertP(txn, row, c.key(), value);
    } else {
        trigger.storeP(txn, row, c.key(), oldValue, value);
    }
    c.commit(value);
    mLockResult = null;
}
Also used : Transaction(org.cojen.tupl.Transaction)

Example 4 with Transaction

use of org.cojen.tupl.Transaction in project Tupl by cojen.

the class BasicRowScanner method doStep.

protected final R doStep(R row) throws IOException {
    Cursor c = mCursor;
    try {
        a: while (true) {
            LockResult result = toNext(c);
            b: while (true) {
                while (c.key() == null) {
                    if (!mController.next()) {
                        break a;
                    }
                    setEvaluator(mController.evaluator());
                    Transaction txn = c.link();
                    mCursor = c = mController.newCursor(mTable.mSource, txn);
                    toFirst(c);
                }
                try {
                    R decoded = decodeRow(c, result, row);
                    if (decoded != null) {
                        mRow = decoded;
                        return decoded;
                    }
                } catch (StoppedCursorException e) {
                    if (result == LockResult.ACQUIRED) {
                        c.link().unlock();
                        unlocked();
                    }
                    continue b;
                }
                if (result == LockResult.ACQUIRED) {
                    c.link().unlock();
                    unlocked();
                }
                continue a;
            }
        }
    } catch (UnpositionedCursorException e) {
    } catch (Throwable e) {
        throw RowUtils.fail(this, e);
    }
    finished();
    return null;
}
Also used : LockResult(org.cojen.tupl.LockResult) UnpositionedCursorException(org.cojen.tupl.UnpositionedCursorException) Transaction(org.cojen.tupl.Transaction) Cursor(org.cojen.tupl.Cursor)

Example 5 with Transaction

use of org.cojen.tupl.Transaction in project Tupl by cojen.

the class IndexBackfill method doRun.

/**
 * @return false if closed
 */
private boolean doRun() throws IOException {
    var primaryBatch = new byte[100 * 2][];
    var secondaryBatch = new byte[primaryBatch.length][];
    Transaction txn = mRowStore.mDatabase.newTransaction();
    txn.lockMode(LockMode.READ_COMMITTED);
    txn.lockTimeout(-1, null);
    txn.durabilityMode(DurabilityMode.NO_REDO);
    try (Cursor c = mManager.mPrimaryIndex.newCursor(txn)) {
        c.autoload(mAutoload);
        c.first();
        int length = 0;
        while (true) {
            byte[] key = c.key();
            if (key == null) {
                if (length > 0) {
                    if (!addBatch(primaryBatch, secondaryBatch, length)) {
                        return false;
                    }
                }
                break;
            }
            primaryBatch[length++] = key;
            primaryBatch[length++] = c.value();
            if (length >= primaryBatch.length) {
                if (!addBatch(primaryBatch, secondaryBatch, length)) {
                    return false;
                }
                length = 0;
            }
            c.next();
        }
    }
    Sorter sorter = mSorter;
    if (sorter == null) {
        return false;
    }
    Index newIndex;
    try {
        newIndex = sorter.finish();
    } catch (InterruptedIOException e) {
        if (mSorter != null) {
            throw e;
        }
        return false;
    }
    Index deleted;
    synchronized (this) {
        deleted = mDeleted;
        if (deleted == null) {
            return false;
        }
        // Lock all triggers to prevent concurrent modifications, and change their behavior
        // now that backfill is finishing.
        withTriggerLock(() -> {
            mNewSecondaryIndex = newIndex;
        });
    }
    txn.lockMode(LockMode.UPGRADABLE_READ);
    try (Cursor secondaryCursor = mSecondaryIndex.newCursor(txn);
        // secondary index entry suffices.
        Cursor deletedCursor = deleted.newCursor(Transaction.BOGUS)) {
        secondaryCursor.first();
        for (byte[] key; (key = secondaryCursor.key()) != null; secondaryCursor.next()) {
            deletedCursor.findNearby(key);
            if (deletedCursor.value() == null) {
                newIndex.store(txn, key, secondaryCursor.value());
            } else {
                deletedCursor.delete();
            }
            secondaryCursor.commit(null);
        }
    }
    // deadlocks. Proper lock acquisition order is mSecondaryIndex and then mDeleted.
    try (Cursor deletedCursor = deleted.newCursor(Transaction.BOGUS)) {
        deletedCursor.first();
        for (byte[] key; (key = deletedCursor.key()) != null; deletedCursor.next()) {
            newIndex.lockUpgradable(txn, key);
            try {
                deletedCursor.load();
                if (deletedCursor.value() != null) {
                    newIndex.store(txn, key, null);
                    deletedCursor.store(null);
                    txn.commit();
                }
            } finally {
                txn.exit();
            }
        }
    }
    // Swap the fully populated new secondary index with the original, which is now
    // empty. As a side-effect, the contents of the new secondary index which was temporary
    // are now associated with a real index, and the original secondary is associated with
    // the temporary index.
    withTriggerLock(() -> {
        try {
            mRowStore.mDatabase.rootSwap(newIndex, mSecondaryIndex);
        } catch (IOException e) {
            throw RowUtils.rethrow(e);
        }
        // Backfill is finished, so stop tracking changes.
        mDeleted = null;
        mNewSecondaryIndex = null;
    });
    try {
        // Eagerly delete the temporary index.
        mRowStore.mDatabase.deleteIndex(newIndex).run();
    } catch (Exception e) {
    // Ignore.
    }
    try {
        // Eagerly delete the temporary index.
        mRowStore.mDatabase.deleteIndex(deleted).run();
    } catch (Exception e) {
    // Ignore.
    }
    return true;
}
Also used : InterruptedIOException(java.io.InterruptedIOException) Transaction(org.cojen.tupl.Transaction) Sorter(org.cojen.tupl.Sorter) Index(org.cojen.tupl.Index) IOException(java.io.IOException) InterruptedIOException(java.io.InterruptedIOException) Cursor(org.cojen.tupl.Cursor) IOException(java.io.IOException) ClosedIndexException(org.cojen.tupl.ClosedIndexException) InterruptedIOException(java.io.InterruptedIOException)

Aggregations

Transaction (org.cojen.tupl.Transaction)36 Cursor (org.cojen.tupl.Cursor)12 Index (org.cojen.tupl.Index)10 LockMode (org.cojen.tupl.LockMode)8 LockResult (org.cojen.tupl.LockResult)8 Database (org.cojen.tupl.Database)6 UnpositionedCursorException (org.cojen.tupl.UnpositionedCursorException)5 IOException (java.io.IOException)4 UnmodifiableReplicaException (org.cojen.tupl.UnmodifiableReplicaException)4 PrepareHandler (org.cojen.tupl.ext.PrepareHandler)4 LinkedBlockingQueue (java.util.concurrent.LinkedBlockingQueue)3 WeakReference (java.lang.ref.WeakReference)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 TreeMap (java.util.TreeMap)2 ConcurrentSkipListMap (java.util.concurrent.ConcurrentSkipListMap)2 TimeUnit (java.util.concurrent.TimeUnit)2 Label (org.cojen.maker.Label)2 MethodMaker (org.cojen.maker.MethodMaker)2 Variable (org.cojen.maker.Variable)2