Fix checkstyle warnings for config-netconf-connector
[controller.git] / opendaylight / netconf / config-netconf-connector / src / main / java / org / opendaylight / controller / netconf / confignetconfconnector / osgi / YangStoreServiceImpl.java
1 /*
2  * Copyright (c) 2013 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
9 package org.opendaylight.controller.netconf.confignetconfconnector.osgi;
10
11 import java.lang.ref.SoftReference;
12 import java.util.concurrent.atomic.AtomicReference;
13 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
14 import org.slf4j.Logger;
15 import org.slf4j.LoggerFactory;
16
17 public class YangStoreServiceImpl implements YangStoreService {
18     private static final Logger LOG = LoggerFactory.getLogger(YangStoreServiceImpl.class);
19
20     /**
21      * This is a rather interesting locking model. We need to guard against both the
22      * cache expiring from GC and being invalidated by schema context change. The
23      * context can change while we are doing processing, so we do not want to block
24      * it, so no synchronization can happen on the methods.
25      *
26      * So what we are doing is the following:
27      *
28      * We synchronize with GC as usual, using a SoftReference.
29      *
30      * The atomic reference is used to synchronize with {@link #refresh()}, e.g. when
31      * refresh happens, it will push a SoftReference(null), e.g. simulate the GC. Now
32      * that may happen while the getter is already busy acting on the old schema context,
33      * so it needs to understand that a refresh has happened and retry. To do that, it
34      * attempts a CAS operation -- if it fails, in knows that the SoftReference has
35      * been replaced and thus it needs to retry.
36      *
37      * Note that {@link #getYangStoreSnapshot()} will still use synchronize() internally
38      * to stop multiple threads doing the same work.
39      */
40     private final AtomicReference<SoftReference<YangStoreSnapshotImpl>> ref = new AtomicReference<>(new SoftReference<YangStoreSnapshotImpl>(null));
41     private final SchemaContextProvider service;
42
43     public YangStoreServiceImpl(final SchemaContextProvider service) {
44         this.service = service;
45     }
46
47     @Override
48     public synchronized YangStoreSnapshotImpl getYangStoreSnapshot() throws YangStoreException {
49         SoftReference<YangStoreSnapshotImpl> r = ref.get();
50         YangStoreSnapshotImpl ret = r.get();
51
52         while (ret == null) {
53             // We need to be compute a new value
54             ret = new YangStoreSnapshotImpl(service.getSchemaContext());
55
56             if (!ref.compareAndSet(r, new SoftReference<>(ret))) {
57                 LOG.debug("Concurrent refresh detected, recomputing snapshot");
58                 r = ref.get();
59                 ret = null;
60             }
61         }
62
63         return ret;
64     }
65
66     /**
67      * Called when schema context changes, invalidates cache.
68      */
69     public void refresh() {
70         ref.set(new SoftReference<YangStoreSnapshotImpl>(null));
71     }
72 }