object alloc version persistent (but not yet loaded to transaction)

This commit is contained in:
2024-12-04 23:25:54 +01:00
parent 6da883fef9
commit aa69ae13a4
6 changed files with 36 additions and 15 deletions

View File

@@ -14,6 +14,11 @@ public class CurrentTransaction implements Transaction {
@Inject
TransactionManager transactionManager;
@Override
public long getId() {
return transactionManager.current().getId();
}
@Override
public <T extends JData> Optional<T> getObject(Class<T> type, JObjectKey key, LockingStrategy strategy) {
return transactionManager.current().getObject(type, key, strategy);

View File

@@ -43,7 +43,6 @@ public class JObjectManager {
private static final Cleaner CLEANER = Cleaner.create();
final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
long lastWriteTx = -1; // FIXME: This should be persistent
public JDataWrapper(T referent) {
super(referent);
@@ -58,7 +57,6 @@ public class JObjectManager {
return "JDataWrapper{" +
"ref=" + get() +
", lock=" + lock +
", lastWriteTx=" + lastWriteTx +
'}';
}
}
@@ -155,7 +153,7 @@ public class JObjectManager {
public <T extends JData> Optional<TransactionObject<T>> getWriteLocked(Class<T> type, JObjectKey key) {
var got = JObjectManager.this.getLocked(type, key, true);
if (got == null) return Optional.empty();
if (got.wrapper().lastWriteTx >= _txId) {
if (got.obj.getVersion() >= _txId) {
got.wrapper().lock.writeLock().unlock();
throw new IllegalStateException("Serialization race");
}
@@ -170,7 +168,9 @@ public class JObjectManager {
}
public void commit(TransactionPrivate tx) {
// This also holds the weak references
var toUnlock = new LinkedList<VoidFn>();
var toFlush = new LinkedList<TxRecord.TxObjectRecordWrite<?>>();
var toPut = new LinkedList<TxRecord.TxObjectRecordNew<?>>();
var toLock = new ArrayList<TxRecord.TxObjectRecordOptimistic<?>>();
@@ -223,14 +223,13 @@ public class JObjectManager {
for (var dep : dependencies) {
Log.trace("Checking dependency " + dep.toString());
var current = _objects.get(dep.data().getKey());
var current = _objects.get(dep.data().getKey()).get();
if (current.get() != dep.data()) {
throw new IllegalStateException("Object changed during transaction: " + current.get() + " vs " + dep.data());
}
// Checked above
assert current == dep.data();
if (current.lastWriteTx >= tx.getId()) {
throw new IllegalStateException("Serialization hazard: " + current.lastWriteTx + " vs " + tx.getId());
if (current.getVersion() >= tx.getId()) {
throw new IllegalStateException("Serialization hazard: " + current.getVersion() + " vs " + tx.getId());
}
}
@@ -252,7 +251,7 @@ public class JObjectManager {
var newWrapper = new JDataWrapper<>(record.copy().wrapped());
newWrapper.lock.writeLock().lock();
if (!_objects.replace(record.copy().wrapped().getKey(), current, newWrapper)) {
assert false;
assert false; // Should not happen, as the object is locked
throw new IllegalStateException("Object changed during transaction after locking: " + current.get() + " vs " + record.copy().wrapped());
}
toUnlock.add(newWrapper.lock.writeLock()::unlock);
@@ -266,10 +265,10 @@ public class JObjectManager {
// Really flushing to storage
written.forEach(obj -> {
Log.trace("Flushing object " + obj.getKey());
assert obj.getVersion() == tx.getId();
var key = obj.getKey();
var data = objectSerializer.serialize(obj);
objectStorage.writeObject(key, data);
_objects.get(key).lastWriteTx = tx.getId(); // FIXME:
});
Log.tracef("Committing transaction %d to storage", tx.getId());

View File

@@ -7,6 +7,8 @@ import java.util.Optional;
// The transaction interface actually used by user code to retrieve objects
public interface Transaction {
long getId();
<T extends JData> Optional<T> getObject(Class<T> type, JObjectKey key, LockingStrategy strategy);
<T extends JData> void putObject(JData obj);

View File

@@ -0,0 +1,16 @@
package com.usatiuk.dhfs.objects.transaction;
import com.usatiuk.objects.common.runtime.JDataAllocVersionProvider;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
@Singleton
public class TransactionObjectAllocVersionProvider implements JDataAllocVersionProvider {
@Inject
Transaction transaction;
public long getVersion() {
return transaction.getId();
}
}

View File

@@ -4,6 +4,5 @@ import java.util.Collection;
// The transaction interface actually used by user code to retrieve objects
public interface TransactionPrivate extends Transaction{
long getId();
Collection<TxRecord.TxObjectRecord<?>> drain();
}

View File

@@ -50,19 +50,19 @@ public class ObjectsTest {
void createCreateObject() {
{
txm.begin();
var newParent = alloc.create(Parent.class, new JObjectKey("Parent"));
var newParent = alloc.create(Parent.class, new JObjectKey("Parent7"));
newParent.setLastName("John");
curTx.putObject(newParent);
txm.commit();
}
Assertions.assertThrows(Exception.class, () -> txm.run(() -> {
var newParent = alloc.create(Parent.class, new JObjectKey("Parent"));
var newParent = alloc.create(Parent.class, new JObjectKey("Parent7"));
newParent.setLastName("John2");
curTx.putObject(newParent);
}));
{
txm.begin();
var parent = curTx.getObject(Parent.class, new JObjectKey("Parent")).orElse(null);
var parent = curTx.getObject(Parent.class, new JObjectKey("Parent7")).orElse(null);
Assertions.assertEquals("John", parent.getLastName());
txm.commit();
}