private <A> A getNoLock(long recid, Serializer<A> serializer) { if (fullTx) { Fun.Tuple2 tu = mod.get(recid); if (tu != null) { if (tu.a == TOMBSTONE) return null; return (A) tu.a; } } Object oldVal = old.get(recid); if (oldVal != null) { if (oldVal == TOMBSTONE) return null; return (A) oldVal; } return TxEngine.this.get(recid, serializer); }
@Override public <A> void update(long recid, A value, Serializer<A> serializer) { if (!fullTx) throw new UnsupportedOperationException("read-only"); commitLock.readLock().lock(); try { mod.put(recid, Fun.t2(value, serializer)); } finally { commitLock.readLock().unlock(); } }
@Override public <A> long put(A value, Serializer<A> serializer) { if (!fullTx) throw new UnsupportedOperationException("read-only"); commitLock.writeLock().lock(); try { Long recid = preallocRecidTake(); usedPreallocatedRecids.add(recid); mod.put(recid, Fun.t2(value, serializer)); return recid; } finally { commitLock.writeLock().unlock(); } }
@Override public <A> boolean compareAndSwap( long recid, A expectedOldValue, A newValue, Serializer<A> serializer) { if (!fullTx) throw new UnsupportedOperationException("read-only"); commitLock.readLock().lock(); try { Lock lock = locks[Store.lockPos(recid)].writeLock(); lock.lock(); try { A oldVal = getNoLock(recid, serializer); boolean ret = oldVal != null && oldVal.equals(expectedOldValue); if (ret) { mod.put(recid, Fun.t2(newValue, serializer)); } return ret; } finally { lock.unlock(); } } finally { commitLock.readLock().unlock(); } }
@Override public void commit() { if (!fullTx) throw new UnsupportedOperationException("read-only"); commitLock.writeLock().lock(); try { if (closed) return; if (uncommitedData) throw new IllegalAccessError("uncomitted data"); txs.remove(ref); cleanTxQueue(); if (pojo.hasUnsavedChanges()) pojo.save(this); // check no other TX has modified our data LongMap.LongMapIterator oldIter = old.longMapIterator(); while (oldIter.moveToNext()) { long recid = oldIter.key(); for (Reference<Tx> ref2 : txs) { Tx tx = ref2.get(); if (tx == this || tx == null) continue; if (tx.mod.containsKey(recid)) { close(); throw new TxRollbackException(); } } } LongMap.LongMapIterator<Fun.Tuple2> iter = mod.longMapIterator(); while (iter.moveToNext()) { long recid = iter.key(); if (old.containsKey(recid)) { close(); throw new TxRollbackException(); } } iter = mod.longMapIterator(); while (iter.moveToNext()) { long recid = iter.key(); Fun.Tuple2 val = iter.value(); Serializer ser = (Serializer) val.b; Object old = superGet(recid, ser); if (old == null) old = TOMBSTONE; for (Reference<Tx> txr : txs) { Tx tx = txr.get(); if (tx == null || tx == this) continue; tx.old.putIfAbsent(recid, old); } if (val.a == TOMBSTONE) { superDelete(recid, ser); } else { superUpdate(recid, val.a, ser); } } // there are no conflicts, so update the POJO in parent // TODO sort of hack, is it thread safe? getWrappedEngine().getSerializerPojo().registered = pojo.registered; superCommit(); close(); } finally { commitLock.writeLock().unlock(); } }
@Override public void close() { closed = true; old.clear(); ref.clear(); }