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