2 * Copyright (c) 2017 Cisco and/or its affiliates.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package io.fd.hc2vpp.v3po.interfacesstate.cache;
19 import static io.fd.hc2vpp.common.translate.util.JvppReplyConsumer.INSTANCE;
20 import static java.util.stream.Collectors.toMap;
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;
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;
44 * Manager for dump data of interfaces/sub-interfaces
46 final class InterfaceCacheDumpManagerImpl implements InterfaceCacheDumpManager {
48 private static final Logger LOG = LoggerFactory.getLogger(InterfaceCacheDumpManagerImpl.class);
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;
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));
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);
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);
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);
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);
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,
97 final SwInterfaceDetailsReplyDump reply =
98 specificDumpManager.getDump(identifier, ctx.getModificationCache(), interfaceName)
99 .or(new SwInterfaceDetailsReplyDump());
101 if (reply.swInterfaceDetails.isEmpty()) {
105 return reply.swInterfaceDetails.get(0);
108 private Map<String, SwInterfaceDetails> initMapAndGet(final InstanceIdentifier<?> identifier, final ReadContext ctx)
109 throws ReadFailedException {
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());
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());
126 LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
127 getInterfaceName(ctx, elt),
132 final Map<String, SwInterfaceDetails> freshIndex = dump.swInterfaceDetails.stream()
133 .collect(toMap(detail -> getInterfaceName(ctx, detail),
135 putMap(freshIndex, ctx);
141 private String getInterfaceName(final ReadContext ctx, final SwInterfaceDetails elt) {
142 return namingContext.getName(elt.swIfIndex, ctx.getMappingContext());
145 private static Map<String, SwInterfaceDetails> getMap(final ReadContext ctx) {
146 return (Map<String, SwInterfaceDetails>) ctx.getModificationCache().get(BY_NAME_INDEX_KEY);
149 private static void putMap(final Map<String, SwInterfaceDetails> map, final ReadContext ctx) {
150 ctx.getModificationCache().put(BY_NAME_INDEX_KEY, map);
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)
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)
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;
179 final CompletableFuture<SwInterfaceDetailsReplyDump>
180 swInterfaceDetailsReplyDumpCompletableFuture = api.swInterfaceDump(request).toCompletableFuture();
181 return INSTANCE.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, identifier);
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;
192 final CompletableFuture<SwInterfaceDetailsReplyDump>
193 swInterfaceDetailsReplyDumpCompletableFuture = api.swInterfaceDump(request).toCompletableFuture();
194 return INSTANCE.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, identifier);