2 * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.cluster.datastore;
10 import akka.actor.ActorSelection;
11 import com.google.common.base.FinalizablePhantomReference;
12 import com.google.common.base.FinalizableReferenceQueue;
13 import java.util.List;
15 import java.util.concurrent.ConcurrentHashMap;
16 import java.util.concurrent.atomic.AtomicBoolean;
17 import org.opendaylight.controller.cluster.datastore.identifiers.TransactionIdentifier;
18 import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction;
19 import org.opendaylight.controller.cluster.datastore.utils.ActorContext;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
24 * A PhantomReference that closes remote transactions for a TransactionProxy when it's
25 * garbage collected. This is used for read-only transactions as they're not explicitly closed
26 * by clients. So the only way to detect that a transaction is no longer in use and it's safe
27 * to clean up is when it's garbage collected. It's inexact as to when an instance will be GC'ed
28 * but TransactionProxy instances should generally be short-lived enough to avoid being moved
29 * to the old generation space and thus should be cleaned up in a timely manner as the GC
30 * runs on the young generation (eden, swap1...) space much more frequently.
32 final class TransactionProxyCleanupPhantomReference
33 extends FinalizablePhantomReference<TransactionProxy> {
34 private static final Logger LOG = LoggerFactory.getLogger(TransactionProxyCleanupPhantomReference.class);
36 * Used to enqueue the PhantomReferences for read-only TransactionProxy instances. The
37 * FinalizableReferenceQueue is safe to use statically in an OSGi environment as it uses some
38 * trickery to clean up its internal thread when the bundle is unloaded.
40 private static final FinalizableReferenceQueue phantomReferenceQueue =
41 new FinalizableReferenceQueue();
44 * This stores the TransactionProxyCleanupPhantomReference instances statically, This is
45 * necessary because PhantomReferences need a hard reference so they're not garbage collected.
46 * Once finalized, the TransactionProxyCleanupPhantomReference removes itself from this map
47 * and thus becomes eligible for garbage collection.
49 private static final Map<TransactionProxyCleanupPhantomReference,
50 TransactionProxyCleanupPhantomReference> phantomReferenceCache =
51 new ConcurrentHashMap<>();
53 private final List<ActorSelection> remoteTransactionActors;
54 private final AtomicBoolean remoteTransactionActorsMB;
55 private final ActorContext actorContext;
56 private final TransactionIdentifier identifier;
58 private TransactionProxyCleanupPhantomReference(TransactionProxy referent) {
59 super(referent, phantomReferenceQueue);
61 // Note we need to cache the relevant fields from the TransactionProxy as we can't
62 // have a hard reference to the TransactionProxy instance itself.
64 remoteTransactionActors = referent.remoteTransactionActors;
65 remoteTransactionActorsMB = referent.remoteTransactionActorsMB;
66 actorContext = referent.actorContext;
67 identifier = referent.getIdentifier();
70 static void track(TransactionProxy referent) {
71 final TransactionProxyCleanupPhantomReference ret = new TransactionProxyCleanupPhantomReference(referent);
72 phantomReferenceCache.put(ret, ret);
76 public void finalizeReferent() {
77 LOG.trace("Cleaning up {} Tx actors for TransactionProxy {}",
78 remoteTransactionActors.size(), identifier);
80 phantomReferenceCache.remove(this);
82 // Access the memory barrier volatile to ensure all previous updates to the
83 // remoteTransactionActors list are visible to this thread.
85 if(remoteTransactionActorsMB.get()) {
86 for(ActorSelection actor : remoteTransactionActors) {
87 LOG.trace("Sending CloseTransaction to {}", actor);
88 actorContext.sendOperationAsync(actor, CloseTransaction.INSTANCE.toSerializable());