b6e85098260c46140828f69c8b1d7c9f2d02d3f6
[hc2vpp.git] /
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package io.fd.hc2vpp.v3po.interfacesstate.cache;
18
19 import static io.fd.hc2vpp.common.translate.util.JvppReplyConsumer.INSTANCE;
20 import static java.util.stream.Collectors.toMap;
21
22 import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
23 import io.fd.hc2vpp.common.translate.util.NamingContext;
24 import io.fd.honeycomb.translate.ModificationCache;
25 import io.fd.honeycomb.translate.read.ReadContext;
26 import io.fd.honeycomb.translate.read.ReadFailedException;
27 import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
28 import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
29 import io.fd.honeycomb.translate.util.read.cache.StaticCacheKeyFactory;
30 import io.fd.jvpp.core.dto.SwInterfaceDetails;
31 import io.fd.jvpp.core.dto.SwInterfaceDetailsReplyDump;
32 import io.fd.jvpp.core.dto.SwInterfaceDump;
33 import io.fd.jvpp.core.future.FutureJVppCore;
34 import java.util.Map;
35 import java.util.concurrent.CompletableFuture;
36 import java.util.stream.Stream;
37 import javax.annotation.Nonnull;
38 import javax.annotation.Nullable;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * Manager for dump data of interfaces/sub-interfaces
45  */
46 final class InterfaceCacheDumpManagerImpl implements InterfaceCacheDumpManager {
47
48     private static final Logger LOG = LoggerFactory.getLogger(InterfaceCacheDumpManagerImpl.class);
49
50     // byNameIndex must be cached, not held as reference here, to have it destroyed with cache after transaction
51     static final String BY_NAME_INDEX_KEY = InterfaceCacheDumpManagerImpl.class.getName() + "_byNameIndex";
52     private NamingContext namingContext;
53     private final DumpCacheManager<SwInterfaceDetailsReplyDump, String> specificDumpManager;
54     private final DumpCacheManager<SwInterfaceDetailsReplyDump, Void> fullDumpManager;
55
56     InterfaceCacheDumpManagerImpl(@Nonnull final FutureJVppCore jvpp,
57                                   @Nonnull final NamingContext namingContext) {
58         this.namingContext = namingContext;
59         specificDumpManager = specificInterfaceDumpManager(jvpp);
60         fullDumpManager = fullInterfaceDumpManager(jvpp,
61                 new StaticCacheKeyFactory(InterfaceCacheDumpManagerImpl.class.getName() + "_dump", SwInterfaceDetailsReplyDump.class));
62     }
63
64     @Override
65     @Nonnull
66     public synchronized Stream<SwInterfaceDetails> getInterfaces(@Nonnull final InstanceIdentifier<?> identifier,
67                                                                  @Nonnull final ReadContext ctx)
68             throws ReadFailedException {
69         LOG.debug("Reading all interfaces[{}]", identifier);
70         return initMapAndGet(identifier, ctx).entrySet().stream().map(Map.Entry::getValue);
71     }
72
73     @Override
74     @Nullable
75     public synchronized SwInterfaceDetails getInterfaceDetail(@Nonnull final InstanceIdentifier<?> identifier,
76                                                               @Nonnull final ReadContext ctx,
77                                                               @Nonnull final String interfaceName)
78             throws ReadFailedException {
79         final Map<String, SwInterfaceDetails> interfaceIndex = getMap(ctx);
80
81         // does not attempt to cover cases with concurrent updates, as tx should be atomic
82         if (interfaceIndex != null) {
83             // tries to find interface in map
84             return interfaceIndex.get(interfaceName);
85         } else {
86             // if map is not present, use specific dump(it will be cached standard way, under key constructed from IID)
87             return dumpSpecificDetail(identifier, ctx, interfaceName);
88         }
89     }
90
91     private SwInterfaceDetails dumpSpecificDetail(@Nonnull final InstanceIdentifier<?> identifier,
92                                                   @Nonnull final ReadContext ctx,
93                                                   @Nonnull final String interfaceName)
94             throws ReadFailedException {
95         LOG.debug("Interface {} not present in cached data, performing specific dump[{}]", interfaceName,
96                 identifier);
97         final SwInterfaceDetailsReplyDump reply =
98                 specificDumpManager.getDump(identifier, ctx.getModificationCache(), interfaceName)
99                         .or(new SwInterfaceDetailsReplyDump());
100
101         if (reply.swInterfaceDetails.isEmpty()) {
102             return null;
103         }
104
105         return reply.swInterfaceDetails.get(0);
106     }
107
108     private Map<String, SwInterfaceDetails> initMapAndGet(final InstanceIdentifier<?> identifier, final ReadContext ctx)
109             throws ReadFailedException {
110
111         final ModificationCache cache = ctx.getModificationCache();
112         if (!cache.containsKey(BY_NAME_INDEX_KEY)) {
113             LOG.debug("Performing dump[{}]", identifier);
114             final SwInterfaceDetailsReplyDump dump =
115                     fullDumpManager.getDump(identifier, cache)
116                             .or(new SwInterfaceDetailsReplyDump());
117
118             // naming context initialization must be done here, as it is uses getName in next step, therefore it would
119             // create artificial mapping for every interface, because this happens before interface dump is processed
120             dump.swInterfaceDetails.forEach((elt) -> {
121                 // Store interface name from VPP in context if not yet present
122                 if (!namingContext.containsName(elt.swIfIndex, ctx.getMappingContext())) {
123                     namingContext.addName(elt.swIfIndex, ByteDataTranslator.INSTANCE.toString(elt.interfaceName),
124                             ctx.getMappingContext());
125                 }
126                 LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
127                         getInterfaceName(ctx, elt),
128                         elt.interfaceName,
129                         elt.swIfIndex);
130             });
131
132             final Map<String, SwInterfaceDetails> freshIndex = dump.swInterfaceDetails.stream()
133                     .collect(toMap(detail -> getInterfaceName(ctx, detail),
134                             detail -> detail));
135             putMap(freshIndex, ctx);
136         }
137
138         return getMap(ctx);
139     }
140
141     private String getInterfaceName(final ReadContext ctx, final SwInterfaceDetails elt) {
142         return namingContext.getName(elt.swIfIndex, ctx.getMappingContext());
143     }
144
145     private static Map<String, SwInterfaceDetails> getMap(final ReadContext ctx) {
146         return (Map<String, SwInterfaceDetails>) ctx.getModificationCache().get(BY_NAME_INDEX_KEY);
147     }
148
149     private static void putMap(final Map<String, SwInterfaceDetails> map, final ReadContext ctx) {
150         ctx.getModificationCache().put(BY_NAME_INDEX_KEY, map);
151     }
152
153
154     private static DumpCacheManager<SwInterfaceDetailsReplyDump, Void> fullInterfaceDumpManager(
155             final FutureJVppCore jvpp,
156             final StaticCacheKeyFactory cacheKeyFactory) {
157         return new DumpCacheManager.DumpCacheManagerBuilder<SwInterfaceDetailsReplyDump, Void>()
158                 .withExecutor(fullInterfaceDumpExecutor(jvpp))
159                 .withCacheKeyFactory(cacheKeyFactory)
160                 .acceptOnly(SwInterfaceDetailsReplyDump.class)
161                 .build();
162     }
163
164     private static DumpCacheManager<SwInterfaceDetailsReplyDump, String> specificInterfaceDumpManager(
165             final FutureJVppCore jvpp) {
166         return new DumpCacheManager.DumpCacheManagerBuilder<SwInterfaceDetailsReplyDump, String>()
167                 .withExecutor(specificInterfaceDumpExecutor(jvpp))
168                 .acceptOnly(SwInterfaceDetailsReplyDump.class)
169                 .build();
170     }
171
172     private static EntityDumpExecutor<SwInterfaceDetailsReplyDump, Void> fullInterfaceDumpExecutor(
173             final FutureJVppCore api) {
174         return (identifier, params) -> {
175             final SwInterfaceDump request = new SwInterfaceDump();
176             request.nameFilter = "".getBytes();
177             request.nameFilterValid = 0;
178
179             final CompletableFuture<SwInterfaceDetailsReplyDump>
180                     swInterfaceDetailsReplyDumpCompletableFuture = api.swInterfaceDump(request).toCompletableFuture();
181             return INSTANCE.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, identifier);
182         };
183     }
184
185     private static EntityDumpExecutor<SwInterfaceDetailsReplyDump, String> specificInterfaceDumpExecutor(
186             final FutureJVppCore api) {
187         return (identifier, ifaceName) -> {
188             final SwInterfaceDump request = new SwInterfaceDump();
189             request.nameFilter = ifaceName.getBytes();
190             request.nameFilterValid = 1;
191
192             final CompletableFuture<SwInterfaceDetailsReplyDump>
193                     swInterfaceDetailsReplyDumpCompletableFuture = api.swInterfaceDump(request).toCompletableFuture();
194             return INSTANCE.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, identifier);
195         };
196     }
197 }