private void putToCache(StateRecord r) { if (useCache) { synchronized (cachedRecords) { cachedRecords.put(r.getId(), new WeakReference<StateRecord>(r)); } } }
private void putToCache(StateRecord r) { if (useCache) { synchronized (cachedRecords) { cachedRecords.put(r.getId(), new WeakReference<StateRecord>(r)); } synchronized (cachedRecordsById) { cachedRecordsById.put(r.getRecordId(), new WeakReference<StateRecord>(r)); } } }
private void sanitateRecord(StateRecord r) { try { if(isShuttingDown) return; resync(r.getId()); } catch (Exception e) { e.printStackTrace(); } }
public void markTestRecord() { if(ledger != null) { ledger.markTestRecord(this.getId()); } }
public FakeItem(StateRecord record) { hashId = record.getId(); }
@Override public void destroy(StateRecord record) { long recordId = record.getRecordId(); if (recordId == 0) { throw new IllegalStateException("can't destroy record without recordId"); } protect(() -> { synchronized (writeLock) { db.update("DELETE FROM ledger WHERE id = ?", recordId); } synchronized (cachedRecords) { cachedRecords.remove(record.getId()); } return null; }); }
@Deprecated public @NonNull Binder extendedCheckItem(HashId itemId) { ItemResult ir = checkItem(itemId); Binder result = Binder.of("itemResult", ir); if (ir != null && ir.state == ItemState.LOCKED) { ir.lockedById = ledger.getLockOwnerOf(itemId).getId(); } return result; }
@Override public void reload(StateRecord stateRecord) throws StateRecord.NotFoundException { try { try (ResultSet rs = db.queryRow("SELECT * FROM ledger WHERE hash = ? limit 1", stateRecord.getId().getDigest()) ) { if (rs == null) throw new StateRecord.NotFoundException("record not found"); stateRecord.initFrom(rs); } } catch (Exception e) { throw new RuntimeException("Failed to reload RecordSet", e); } }
@Override public void reload(StateRecord stateRecord) throws StateRecord.NotFoundException { try { try ( PooledDb db = dbPool.db(); ResultSet rs = db.queryRow("SELECT * FROM ledger WHERE hash = ? limit 1", stateRecord.getId().getDigest() ); ) { if (rs == null) throw new StateRecord.NotFoundException("record not found"); stateRecord.initFrom(rs); } catch (Exception e) { e.printStackTrace(); throw e; } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("Failed to reload RecordSet", e); } }
@Override public Map<HashId,StateRecord> findUnfinished() { return protect(() -> { HashMap<HashId, StateRecord> map = new HashMap<>(); try (ResultSet rs = inPool(db -> db.queryRow("select * from sr_find_unfinished()"))) { if (rs != null) { do { StateRecord record = new StateRecord(this, rs); if (record.isExpired()) { record.destroy(); } else { map.put(record.getId(), record); } } while (rs.next()); } } catch (Exception e) { e.printStackTrace(); throw e; } return map; }); }
@Override public String toString() { return "State<"+getId()+"/"+getRecordId()+":"+getState()+":"+getCreatedAt()+"/"+getExpiresAt()+">"; } }
@Override public void destroy(StateRecord record) { long recordId = record.getRecordId(); if (recordId == 0) { throw new IllegalStateException("can't destroy record without recordId"); } protect(() -> { inPool(d -> { d.update("DELETE FROM items WHERE id = ?", recordId); d.update("DELETE FROM ledger WHERE id = ?", recordId); return null; }); synchronized (cachedRecords) { cachedRecords.remove(record.getId()); } synchronized (cachedRecordsById) { cachedRecordsById.remove(record.getRecordId()); } return null; }); }
@Test public void checkLockOwner() throws Exception { ledger.enableCache(true); StateRecord existing = ledger.findOrCreate(HashId.createRandom()); existing.approve(); StateRecord r = ledger.findOrCreate(HashId.createRandom()); StateRecord r1 = r.lockToRevoke(existing.getId()); existing.reload(); r.reload(); assertSameRecords(existing, r1); assertEquals(ItemState.LOCKED, existing.getState()); assertEquals(r.getRecordId(), existing.getLockedByRecordId()); StateRecord currentOwner = ledger.getLockOwnerOf(existing); System.out.println("existing: " + existing.getId()); System.out.println("locker: " + r.getId()); System.out.println("locked: " + r1.getId()); System.out.println("currentOwner: " + currentOwner.getId()); assertSameRecords(r, currentOwner); }
@Test public void destroy() throws Exception { StateRecord r1 = ledger.findOrCreate(HashId.createRandom()); r1.destroy(); assertNull(ledger.getRecord(r1.getId())); }
@Test public void destroy() throws Exception { StateRecord r1 = ledger.findOrCreate(HashId.createRandom()); r1.destroy(); assertNull(ledger.getRecord(r1.getId())); }
protected void assertSameRecords(StateRecord r, StateRecord r1) { assertEquals(r.getId(), r1.getId()); assertEquals(r.getState(), r1.getState()); assertAlmostSame(r.getCreatedAt(), r1.getCreatedAt()); assertEquals(r.getRecordId(), r1.getRecordId()); assertEquals(r.getLockedByRecordId(), r1.getLockedByRecordId()); }
@Test public void createOutputLockRecord() throws Exception { ledger.enableCache(true); StateRecord owner = ledger.findOrCreate(HashId.createRandom()); StateRecord other = ledger.findOrCreate(HashId.createRandom()); HashId id = HashId.createRandom(); StateRecord r1 = owner.createOutputLockRecord(id); r1.reload(); assertEquals(id, r1.getId()); assertEquals(ItemState.LOCKED_FOR_CREATION, r1.getState()); assertEquals(owner.getRecordId(), r1.getLockedByRecordId()); StateRecord r2 = owner.createOutputLockRecord(id); assertSame(r2, r1); assertNull(owner.createOutputLockRecord(other.getId())); // And hacked low level operation must fail too assertNull(ledger.createOutputLockRecord(owner.getRecordId(), other.getId())); }
@Test public void createOutputLockRecord() throws Exception { ledger.enableCache(true); StateRecord owner = ledger.findOrCreate(HashId.createRandom()); StateRecord other = ledger.findOrCreate(HashId.createRandom()); HashId id = HashId.createRandom(); StateRecord r1 = owner.createOutputLockRecord(id); r1.reload(); assertEquals(id, r1.getId()); assertEquals(ItemState.LOCKED_FOR_CREATION, r1.getState()); assertEquals(owner.getRecordId(), r1.getLockedByRecordId()); StateRecord r2 = owner.createOutputLockRecord(id); assertSame(r2, r1); assertNull(owner.createOutputLockRecord(other.getId())); // And hacked low level operation must fail too assertNull(ledger.createOutputLockRecord(owner.getRecordId(), other.getId())); }
@Test public void findOrCreateAndGet() throws Exception { // Atomic new record creation HashId id = HashId.createRandom(); StateRecord r = ledger.findOrCreate(id); assertNotNull(r); assertEquals(id, r.getId()); assertEquals(ItemState.PENDING, r.getState()); assertAlmostSame(ZonedDateTime.now(), r.getCreatedAt()); // returning existing record StateRecord r1 = ledger.findOrCreate(id); assertSameRecords(r, r1); StateRecord r2 = ledger.getRecord(id); assertSameRecords(r, r2); StateRecord r3 = ledger.getRecord(HashId.createRandom()); assert (r3 == null); }
@Test public void findOrCreateAndGet() throws Exception { // Atomic new record creation HashId id = HashId.createRandom(); StateRecord r = ledger.findOrCreate(id); assertNotNull(r); assertEquals(id, r.getId()); assertEquals(ItemState.PENDING, r.getState()); assertAlmostSame(ZonedDateTime.now(), r.getCreatedAt()); // returning existing record StateRecord r1 = ledger.findOrCreate(id); assertSameRecords(r, r1); StateRecord r2 = ledger.getRecord(id); assertSameRecords(r, r2); StateRecord r3 = ledger.getRecord(HashId.createRandom()); assert (r3 == null); }