Search in sources :

Example 36 with Transaction

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

the class TableManager method update.

/**
 * @param table can be null if no table instances exist
 * @param rowType can be null if table is null
 * @param primaryInfo required
 * @param secondaries key is secondary index descriptor, value is index id and state
 */
private void update(AbstractTable<R> table, Class<R> rowType, RowInfo primaryInfo, RowStore rs, Transaction txn, View secondaries) throws IOException {
    int numIndexes = 0;
    try (Cursor c = secondaries.newCursor(txn)) {
        for (c.first(); c.key() != null; c.next()) {
            byte state = c.value()[8];
            if (state != 'D') {
                numIndexes++;
            }
        }
    }
    // Remove stale entries.
    var it = mIndexInfos.keySet().iterator();
    while (it.hasNext()) {
        byte[] desc = it.next();
        if (!secondaries.exists(txn, desc)) {
            it.remove();
            removeIndexBackfill(desc);
        }
    }
    ArrayList<IndexBackfill> newBackfills = null;
    IndexTriggerMaker<R> maker = null;
    if (numIndexes > 0) {
        maker = new IndexTriggerMaker<>(rowType, primaryInfo, numIndexes);
    }
    try (Cursor c = secondaries.newCursor(txn)) {
        int i = 0;
        byte[] desc;
        for (c.first(); (desc = c.key()) != null; c.next()) {
            byte[] value = c.value();
            long indexId = decodeLongLE(value, 0);
            byte state = value[8];
            if (state != 'B') {
                // not "backfill" state
                removeIndexBackfill(desc);
                if (state == 'D') {
                    // "deleting" state
                    continue;
                }
            }
            Index index = rs.mDatabase.indexById(indexId);
            if (index == null) {
                throw new CorruptDatabaseException("Secondary index is missing: " + indexId);
            }
            maker.mSecondaryDescriptors[i] = desc;
            maker.mSecondaryInfos[i] = secondaryInfo(primaryInfo, desc);
            maker.mSecondaryIndexes[i] = index;
            maker.mSecondaryLocks[i] = rs.indexLock(index);
            if (state == 'B') {
                // "backfill" state
                if (mIndexBackfills == null) {
                    mIndexBackfills = new TreeMap<>(KEY_COMPARATOR);
                }
                IndexBackfill<R> backfill = mIndexBackfills.get(desc);
                if (backfill == null) {
                    backfill = maker.makeBackfill(rs, mPrimaryIndex.id(), this, i);
                    mIndexBackfills.put(desc, backfill);
                    if (newBackfills == null) {
                        newBackfills = new ArrayList<>();
                    }
                    newBackfills.add(backfill);
                }
                maker.mBackfills[i] = backfill;
            }
            i++;
        }
    }
    if (mIndexBackfills != null && mIndexBackfills.isEmpty()) {
        mIndexBackfills = null;
    }
    if (table != null && table.supportsSecondaries()) {
        Trigger<R> trigger = null;
        if (maker != null) {
            trigger = maker.makeTrigger(rs, mPrimaryIndex.id());
        }
        table.setTrigger(trigger);
    }
    if (newBackfills != null && !newBackfills.isEmpty()) {
        Worker worker;
        if (mWorkerRef == null || (worker = mWorkerRef.get()) == null) {
            worker = Worker.make(Integer.MAX_VALUE, 10, TimeUnit.SECONDS, r -> {
                Thread t = new Thread(r);
                t.setDaemon(true);
                return t;
            });
            mWorkerRef = new WeakReference<>(worker);
        }
        for (var backfill : newBackfills) {
            // The backfill must also be installed as a listener before it starts.
            rs.mDatabase.addRedoListener(backfill);
            worker.enqueue(backfill);
        }
    }
}
Also used : RowUtils(org.cojen.tupl.rows.RowUtils) CorruptDatabaseException(org.cojen.tupl.CorruptDatabaseException) IOException(java.io.IOException) Table(org.cojen.tupl.Table) ArrayList(java.util.ArrayList) TimeUnit(java.util.concurrent.TimeUnit) List(java.util.List) ConcurrentSkipListMap(java.util.concurrent.ConcurrentSkipListMap) Cursor(org.cojen.tupl.Cursor) TreeMap(java.util.TreeMap) Worker(org.cojen.tupl.util.Worker) Transaction(org.cojen.tupl.Transaction) WeakReference(java.lang.ref.WeakReference) View(org.cojen.tupl.View) Index(org.cojen.tupl.Index) Index(org.cojen.tupl.Index) Cursor(org.cojen.tupl.Cursor) Worker(org.cojen.tupl.util.Worker) CorruptDatabaseException(org.cojen.tupl.CorruptDatabaseException)

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