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);
}
}
}
Aggregations