mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-13 10:45:51 +00:00
Confidence objects now pin themselves when a listener is attached, eliminating a certain class of GC-triggered heisenbug.
This commit is contained in:
parent
5a824f8411
commit
750f469bd3
@ -174,6 +174,15 @@ public class TransactionConfidence implements Serializable {
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason);
|
||||
}
|
||||
|
||||
// This is used to ensure that confidence objects which aren't referenced from anywhere but which have an event
|
||||
// listener set on them don't become eligible for garbage collection. Otherwise the TxConfidenceTable, which only
|
||||
// has weak references to these objects, would not be enough to keep the event listeners working as transactions
|
||||
// propagate around the network - it cannot know directly if the API user is interested in the object, so it uses
|
||||
// heap reachability as a proxy for interest.
|
||||
//
|
||||
// We add ourselves to this set when a listener is added and remove ourselves when the listener list is empty.
|
||||
private static final Set<TransactionConfidence> pinnedConfidenceObjects = Collections.synchronizedSet(new HashSet<TransactionConfidence>());
|
||||
|
||||
/**
|
||||
* <p>Adds an event listener that will be run when this confidence object is updated. The listener will be locked and
|
||||
* is likely to be invoked on a peer thread.</p>
|
||||
@ -186,6 +195,7 @@ public class TransactionConfidence implements Serializable {
|
||||
public void addEventListener(Listener listener, Executor executor) {
|
||||
checkNotNull(listener);
|
||||
listeners.addIfAbsent(new ListenerRegistration<Listener>(listener, executor));
|
||||
pinnedConfidenceObjects.add(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -204,7 +214,10 @@ public class TransactionConfidence implements Serializable {
|
||||
|
||||
public boolean removeEventListener(Listener listener) {
|
||||
checkNotNull(listener);
|
||||
return ListenerRegistration.removeFromList(listener, listeners);
|
||||
boolean removed = ListenerRegistration.removeFromList(listener, listeners);
|
||||
if (listeners.isEmpty())
|
||||
pinnedConfidenceObjects.remove(this);
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,6 +33,7 @@ public class ListenerRegistration<T> {
|
||||
this.executor = checkNotNull(executor);
|
||||
}
|
||||
|
||||
/** Returns true if the listener was removed, else false. */
|
||||
public static <T> boolean removeFromList(T listener, List<? extends ListenerRegistration<T>> list) {
|
||||
checkNotNull(listener);
|
||||
|
||||
|
@ -35,7 +35,8 @@ public class TxConfidenceTableTest {
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
BriefLogFormatter.init();
|
||||
table = Context.getOrCreate().getConfidenceTable();
|
||||
Context context = new Context();
|
||||
table = context.getConfidenceTable();
|
||||
|
||||
Address to = new ECKey().toAddress(params);
|
||||
Address change = new ECKey().toAddress(params);
|
||||
@ -48,7 +49,26 @@ public class TxConfidenceTableTest {
|
||||
address2 = new PeerAddress(InetAddress.getByAddress(new byte[] { 127, 0, 0, 2 }));
|
||||
address3 = new PeerAddress(InetAddress.getByAddress(new byte[] { 127, 0, 0, 3 }));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void pinHandlers() throws Exception {
|
||||
Transaction tx = new Transaction(params, tx1.bitcoinSerialize());
|
||||
Sha256Hash hash = tx.getHash();
|
||||
table.seen(hash, address1);
|
||||
assertEquals(1, tx.getConfidence().numBroadcastPeers());
|
||||
final int[] seen = new int[1];
|
||||
tx.getConfidence().addEventListener(new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
seen[0] = confidence.numBroadcastPeers();
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
tx = null;
|
||||
System.gc();
|
||||
table.seen(hash, address2);
|
||||
assertEquals(2, seen[0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invAndDownload() throws Exception {
|
||||
// Base case: we see a transaction announced twice and then download it. The count is in the confidence object.
|
||||
|
Loading…
x
Reference in New Issue
Block a user