Fix followerDistributedDataStore tear down
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / ClientBackedTransaction.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.cluster.databroker;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.lang.ref.Cleaner;
13 import java.lang.ref.Cleaner.Cleanable;
14 import org.opendaylight.controller.cluster.access.concepts.TransactionIdentifier;
15 import org.opendaylight.controller.cluster.databroker.actors.dds.AbstractClientHandle;
16 import org.opendaylight.controller.cluster.databroker.actors.dds.ClientTransaction;
17 import org.opendaylight.mdsal.dom.spi.store.AbstractDOMStoreTransaction;
18 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransaction;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 /**
23  * An implementation of {@link DOMStoreTransaction} backed by a {@link ClientTransaction}. It guards against user-level
24  * leaks by maintaining a phantom reference on the backing transaction, which will ensure that the transaction will
25  * be aborted, if it is not otherwise closed, just before this object is garbage-collected.
26  *
27  * @author Robert Varga
28  */
29 abstract class ClientBackedTransaction<T extends AbstractClientHandle<?>> extends
30         AbstractDOMStoreTransaction<TransactionIdentifier> {
31     private static final class Cleanup implements Runnable {
32         private final AbstractClientHandle<?> transaction;
33         private final Throwable allocationContext;
34
35         Cleanup(final AbstractClientHandle<?> transaction, final Throwable allocationContext) {
36             this.transaction = transaction;
37             this.allocationContext = allocationContext;
38         }
39
40         @Override
41         public void run() {
42             if (transaction.abort()) {
43                 LOG.info("Aborted orphan transaction {}", transaction, allocationContext);
44             }
45         }
46     }
47
48     private static final Logger LOG = LoggerFactory.getLogger(ClientBackedTransaction.class);
49     private static final Cleaner CLEANER = Cleaner.create();
50
51     private final T delegate;
52     private final Cleanable cleanable;
53
54     ClientBackedTransaction(final T delegate, final Throwable allocationContext) {
55         super(delegate.getIdentifier());
56         this.delegate = requireNonNull(delegate);
57         this.cleanable = CLEANER.register(this, new Cleanup(delegate, allocationContext));
58     }
59
60     @Override
61     public void close() {
62         delegate.abort();
63         // Run cleaning immediate so the references is not stuck in cleaner queue
64         cleanable.clean();
65     }
66
67     final T delegate() {
68         return delegate;
69     }
70 }